Pretransplant natural antibody levels identify a subset of deceased donor kidney transplant recipients that benefit from infliximab induction

Statistical report


Authors and affiliations

Vojtech Petr1,2, Samuel L. Liu3, Filip Tichanek1, Felix Poppelaars2, Brandon Renner2, Jennifer Laskowski2, Shrey Purohit2, Ming Zhao3, Diana Jalal4,5, Peter S. Heeger6,#, Joshua M. Thurman3,#


1 Institute for Clinical and Experimental Medicine, Prague, Czech Republic
2 Department of Medicine, University of Colorado School of Medicine, Anschutz Medical Campus, Aurora, CO, USA
3 Feinberg Cardiovascular and Renal Research Institute, Northwestern University, Chicago, IL, USA
4 Department of Medicine, Carver College of Medicine, University of Iowa, IA, USA
5 Iowa City VA HCS, Iowa City, IA, USA
6 Departments of Medicine, Surgery and Biomedical Sciences, Cedars Sinai Medical Center, Los Angeles, CA, USA
# Co-senior authors, contributed equally


This is a statistical report of the study titled Pretransplant natural antibody levels identify a subset of deceased donor kidney transplant recipients that benefit from infliximab induction currently under review in the American Journal of Transplantation journal.

When using this code or data, cite the original publication:

TO BE ADDED

BibTex citation for the original publication:

TO BE ADDED


Original GitHub repository: https://github.com/filip-tichanek/infliximab_nAb

Statistical reports can be found here



1 Manuscript text

1.1 Statistical analysis methods

1.1.1 Full version

Analyses were performed in R (version 4.4.2) (R Core Team 2024) and GraphPad Prism (version 10.2.3). Continuous variables are reported as medians with interquartile ranges and categorical variables as counts and percentages. Group comparisons were conducted using the Mann–Whitney test, and correlations were assessed via Spearman’s rank correlation.

Unadjusted effects of covariates (including nAb and their interaction with infliximab) were estimated using complete-case logistic regression for binary outcomes (DGF, infection, and BKV infection) and linear models for eGFR.

For outcome–nAb combinations where the 95% confidence interval of the interaction term did not include the null effect, we fit multivariable Bayesian models with a non-linear interaction between log\(_2\)-transformed nAb levels and infliximab using penalized B-splines with 5 knots (separately for each treatment group). Logistic Bayesian regression was used for binary outcomes, while Bayesian robust regression (Student’s t-distribution) was used for eGFR. Covariates were prespecified based on their well-documented association with kidney transplant outcomes and included donor and recipient sex, HLA mismatch count, KDPI, perfusion event, recipient age, and cold ischemia time.

Missing data (35 for HLA mismatch, 21 for perfusion event, 3 for cold ischemia time) were handled via multiple imputation (80 datasets) using the ‘mice’ package (van Buuren and Groothuis-Oudshoorn 2011). Binary variables were imputed via logistic regression, and numeric variables via predictive mean matching. Bayesian models were run using the ‘brms’ package (Bürkner 2017) with Hamiltonian Monte Carlo sampling (4 chains, 2000 iterations including 1900 warm-ups per each of 80 imputed datasets, yielding 32,000 post-warmup samples). Posterior distributions were summarized by the median (point estimate) and the 2.5th and 97.5th percentiles (95% credible interval, 95% CrI).

Priors for fixed effects were Gaussian, centered at 0 (\(\mu = 0\)), with \(\sigma\) defined as follows:

In logistic model (binary outcomes):

\(\sigma = 4\) for binary predictors

\(\sigma = \frac{2}{\text{SD}(\text{predictor})}\) for numeric predictors

For robust regression (eGFR):

\(\sigma = 4 \times \text{SD}(\text{eGFR})\) for binary predictors

\(\sigma = \frac{2 \times \text{SD}(\text{eGFR})}{\text{SD}(\text{predictor})}\) for numeric predictors

Non-linear effects used Student’s t priors:

Baseline spline: \(df = 3, \mu = 0, \sigma = 0.6\)

Treatment-specific spline: \(df = 3, \mu = 0, \sigma = 0.3\)

Posterior estimates for infliximab effects were obtained at the 5th, 25th, 50th, 75th, and 95th percentiles of nAb levels. We quantified the modulation of infliximab treatment by comparing the posterior distributions of the treatment effect at the 5th and 95th percentiles of nAb levels. For each posterior sample, we computed the ratio of odds ratios (OR at 95th percentile / OR at 5th percentile) in logistic models and the difference in treatment effects (\(\beta_{\text{infliximab}}|\text{nAbs}=95^\text{th}\)\(\beta_{\text{infliximab}}|\text{nAbs}=5^\text{th}\)) in robust regression for eGFR.

Mediation analysis was performed using the ‘bayestestR’ package (Makowski, Ben-Shachar, and Lüdecke 2019) to assess whether infliximab affected eGFR and whether this effect was mediated through DGF. Analyses were conducted separately for individuals with below- and above-median aCL IgG levels.

Because the highest aCL IgG levels were only observed in the control group, we performed a sensitivity analysis by restricting the dataset to patients with aCL IgG levels within the range observed in the infliximab group.

1.1.2 Short version (manuscript)

All analyses were conducted in R (version 4.4.2) and GraphPad Prism (version 10.2.3). Continuous variables are reported as medians with interquartile ranges, and categorical variables as percentages. Spearman’s rank correlation assessed associations.

Unadjusted analyses used logistic regression for binary outcomes (DGF, infection, and BKV infection) and linear models for eGFR, both based on complete cases. When the 95% confidence interval of the interaction term between nAb and infliximab did not include the null effect, multivariable Bayesian models with non-linear interactions (using group-specific B splines) were fitted to using the ‘brms’ R package. These models employed logistic regression for binary outcomes and robust (Student’s t) regression for eGFR, with multiple imputation (80 datasets) for missing data.

Pre-specified covariates included donor and recipient sex, HLA mismatch count, KDPI, perfusion event, recipient age, and cold ischemia time. Posterior distributions were summarized by medians with 95% credible intervals (CrI). To evaluate infliximab treatment effects across different nAb levels, we obtained posterior distributions at the 5th, 25th, 50th, 75th, and 95th percentiles of these levels. To quantify how strongly nAb levels modulate the infliximab effect, we compared infliximab estimates at the 95th and 5th percentiles, reporting the ratio of odds ratios for binary outcomes and the difference in treatment effects for eGFR.

Bayesian mediation analysis (using ‘bayestestR’) was used to assess whether infliximab’s effect on eGFR is mediated through DGF, stratified by above- vs. below-median aCL IgG levels. A sensitivity analysis was performed by restricting the dataset to patients with aCL IgG levels within the range observed in the infliximab group.

A full description of the statistical modeling methods, including prior specifications and posterior sampling details, is provided in the Supplementary Methods and online with the code (https://filip-tichanek.github.io/infliximab_nAb).

1.2 Results

1.2.1 Data Distributions and nAB levels correlations

The distribution of antibody levels across different groups, defined by treatment group and either DGF (aCL) or infection (aPE), is shown in Figure 1. The figure indicates substantial variability in nAB levels and suggests differences across groups.

No correlation was found between IgG levels of aCL and aPE (Supplementary Figure 1). In contrast, IgM antibodies exhibited strong positive correlations among each other, correlations between IgM and IgG of the same epitope (e.g., aCL IgG and aCL IgM) were weaker. Altogether, this suggests that IgG aCL and aPE antibodies serve different purposes and reflect distinct immune responses of individual subjects.

1.2.2 aCL level mediates infliximab effect on DGF risk

Univariable logistic regression suggests that DGF risk may be associated with male recipient sex, HLA mismatch, cold ischemia time, and also infliximab:aCL IgG interaction (Supplementary Table 1), indicating that aCL may modulate the effect of infliximab on DGF risk.

To further explore this possible modulation, we fit a multivariable Bayesian logistic model allowing a non-linear relationship between aCL and DGF risk separately for each treatment group (Table 1). The results are in line with the unadjusted findings: the effect of infliximab varies with aCL IgG level, with the odds ratio for infliximab estimated to be 47 times larger (95% CrI: 4.4 to 610) in patients at the 5th percentile of aCL IgG level (0.29 µg/ml) versus those at the 95th percentile (5.78 µg/ml). Specifically, infliximab is expected to reduce the odds of DGF by 87% for those at the 5th percentile (OR: 0.13, 95% CrI: 0.03 to 0.49, Figure 2), whereas at the 95th percentile (5.78 µg/ml), the odds ratio reverses direction (OR: 6.24, 95% CrI: 1.38 to 30.32).

When we excluded patients in the control group with aCL levels higher than the maximum observed in the infliximab group, results remained consistent (Supplementary Figure 2). A similar pattern is observed for IgM, though the modulation effect is weaker (Supplementary Figure 3, Table 1). Subgroup analysis based on aCL IgG levels \(< median\) or \(\geq median\) also shows a similar pattern: infliximab reduces DGF risk at those with relatively low aCL IgG (OR: 0.21, 95% CrI: 0.06 to 0.64) but exhibits the opposite effect when aCL IgG \(\geq median\) (OR: 2.9, 95% CrI: 1.01 to 8.7).

In short, infliximab very likely reduces DGF risk when aCL is low but tends to increase it with relatively high aCL.

1.2.3 aCL mediates infliximab effect on eGFR

Univariable linear models suggested that eGFR may be associated with low KDPI, absence of DGF, and absence of perfusion event, as well as with the infliximab:aCL IgG interaction (Supplementary Table 2).

A subsequent Bayesian linear model shows a congruent result: infliximab is associated with a small negative to possibly large positive effect on eGFR for patients at the 5th percentile of aCL IgG (β: 7.7, 95% CrI: -2.4 to 17.9) but has likely negative effect at the 95th percentile (β: -17.4, 95% CrI: -30 to -5.1; Table 1; Supplementary Figure 2). Similar patterns emerge for aCL IgM (Supplementary Figure 4) and when excluding control patients whose aCL IgG exceeded the maximum level observed in the infliximab group (Supplementary Figure 5).

In unadjusted analysis, DGF was a strong predictor of eGFR. Since infliximab reduces DGF risk at low aCL but worsens it at high aCL, we tested whether aCL might modulate infliximab’s effect on eGFR via DGF. In patients with aCL below the median, Bayesian mediation analysis showed a positive indirect effect of infliximab on eGFR through reduced DGF risk (ACME: 5.4, 95% CrI: 1.6 to 10.6) and no clear direct effect (ACD: 2.1, 95% CrI: -6.1 to 10.1; Supplementary Table 3). By contrast, for aCL ≥ median, infliximab had a direct negative effect on eGFR (ADE: -11.1, 95% CrI: -19.1 to -2.9) with possible contribution with indirect negative effect via incressing DGF risk (ACME: -2.3, 95% CrI: -6.6 to 0.3).

In conclusion, infliximab may have positive indirect effect on eGFR via reducing DGF risk when aCL is low, but it likely decreases eGFR directly in patients with relatively high aCL.

1.2.4 aPE modulates infliximab effect on infection

Univariable logistic regression showed that infection risk was associated with KDPI and, surprisingly, negatively associated with longer cold ischemia time. There was also an interaction between infliximab and aPE, particularly with co-factor independent aPE (though less clearly with co-factor dependent aPE; Supplementary Table 4).

A Bayesian logistic model allowing a non-linear interaction between infliximab and co-factor independent aPE confirmed that infliximab likely increases infection risk at lower aPE levels (5th and 25th percentiles) but has an uncertain or possibly positive effect at higher levels (Supplementary Figure 6, Table 1). A similar pattern emerged for co-factor dependent aPE IgG (Supplementary Figure 7, Table 1).

Overall, these results suggest infliximab may raise infection risk, especially for patients with relatively low aPE levels.

1.2.5 Infliximab effects on BK viremia risk

Univariable logistic regression suggested that BKV infection risk is generally increased with infliximab, and there was no indication of effect modification by nAB level (Supplementary Table 5).

2 Initiation

Packages

Open code
if (TRUE) {rm(list = ls() )}
if (TRUE) { 
  suppressWarnings(suppressMessages({
    library(tidyverse)
    library(stringr)
    library(stringi)
    library(ggpubr)
    library(emmeans)
    library(gtsummary)
    library(skimr)
    library(car)
    library(RJDBC)
    library(sjPlot)
    library(flextable)
    library(openxlsx)
    library(mgcv)
    library(pROC)
    library(cowplot)
    library(boot)
    library(glmnet)
    library(brms)
    library(projpred)
    library(janitor)
    library(arm)
    library(corrplot)
    library(lubridate)
    library(kableExtra)    
    library(ggdist)
    library(bayesplot)
    library(coxed)
    library(quantreg)
    library(ggbeeswarm)
    library(mgcv)
    library(mice)
    library(MASS)
    library(bayestestR)
     
    # Functions clashes
    select <- dplyr::select
    rename <- dplyr::rename
    mutate <- dplyr::mutate
    recode <- dplyr::recode
    summarize <- dplyr::summarize
    count <- dplyr::count
    
    # Simple math functions
    logit <-function(x){log(x/(1-x))}
    inv_logit <- function(x){exp(x)/(1+exp(x))}
  }))
}

Functions

Open code
run <- function(expr, path, reuse = TRUE) {
  fit <- NULL
  if (reuse) {
    path <- paste0(path, ".Rds")
    fit <- suppressWarnings(try(readRDS(path), silent = TRUE))
    if (inherits(fit, "try-error")) {
      fit <- NULL
    }
  }
  if (is.null(fit)) {
    fit <- eval(substitute(expr))
    if (reuse && !is.null(path) && nzchar(path)) {
      saveRDS(fit, file = path)
    }
  }
  return(fit)
}

Setting seeds and scipen

Open code
set.seed(2025)
options(scipen = 999)

3 Data

Upload data a create relevant variables

Open code
data2 <- read.xlsx(
  "gitignore/data/dataset_updated_4_2024.xlsx")

data2 <- data2 %>%
  mutate(
    GPE_dep_log2 = log2(GPE_dep),
    MPE_dep_log2 = log2(MPE_dep),
    GPE_ind_log2 = log2(GPE_ind),
    MPE_ind_log2 = log2(MPE_ind)
  ) %>%
  mutate(
    GPL_BC_log2 = log2(GPL_BC),
    MPL_BC_log2 = log2(MPL_BC)
  ) %>%
  mutate(CIT = CIT / 60) %>%
  mutate(treatment_group = if_else(
    infliximab == 1, "infiximab", "placebo"
  ))

summary(data2)
##    ID_subject     TNFR1_stain     TNFR2_stain       available      flow    
##  Min.   : 1001   Min.   :0.000   Min.   :0.0000   Min.   :1   Min.   :1    
##  1st Qu.: 5017   1st Qu.:1.000   1st Qu.:0.0000   1st Qu.:1   1st Qu.:1    
##  Median : 8057   Median :2.000   Median :0.0000   Median :1   Median :1    
##  Mean   :17827   Mean   :1.667   Mean   :0.1667   Mean   :1   Mean   :1    
##  3rd Qu.:23007   3rd Qu.:2.000   3rd Qu.:0.0000   3rd Qu.:1   3rd Qu.:1    
##  Max.   :57019   Max.   :2.000   Max.   :2.0000   Max.   :1   Max.   :1    
##                  NA's   :156     NA's   :156                  NA's   :137  
##   ID_sample              GPL               MPL              GPL_BC        
##  Length:180         Min.   : 0.1270   Min.   : 0.7469   Min.   : 0.06879  
##  Class :character   1st Qu.: 0.6315   1st Qu.: 2.3548   1st Qu.: 0.60473  
##  Mode  :character   Median : 0.9434   Median : 4.1302   Median : 0.93076  
##                     Mean   : 1.9069   Mean   : 6.7417   Mean   : 1.91444  
##                     3rd Qu.: 1.7415   3rd Qu.: 7.4118   3rd Qu.: 1.79043  
##                     Max.   :30.7573   Max.   :41.3703   Max.   :30.90609  
##                                                                           
##      MPL_BC           GPE_ind          MPE_ind           GPE_dep      
##  Min.   : 0.0216   Min.   :0.0685   Min.   :0.06700   Min.   :0.0800  
##  1st Qu.: 2.1391   1st Qu.:0.0940   1st Qu.:0.09175   1st Qu.:0.1565  
##  Median : 4.0818   Median :0.1115   Median :0.11250   Median :0.1905  
##  Mean   : 6.6395   Mean   :0.1569   Mean   :0.13474   Mean   :0.2316  
##  3rd Qu.: 7.7745   3rd Qu.:0.1527   3rd Qu.:0.15375   3rd Qu.:0.2492  
##  Max.   :42.7197   Max.   :0.9775   Max.   :0.67250   Max.   :1.3345  
##                    NA's   :1        NA's   :1         NA's   :1       
##     MPE_dep          flow_IgM         flow_IgG        infliximab    
##  Min.   :0.0820   Min.   : 87937   Min.   : 46682   Min.   :0.0000  
##  1st Qu.:0.1310   1st Qu.:172979   1st Qu.: 60076   1st Qu.:0.0000  
##  Median :0.1820   Median :241051   Median : 74844   Median :0.0000  
##  Mean   :0.2127   Mean   :284641   Mean   : 76880   Mean   :0.4944  
##  3rd Qu.:0.2505   3rd Qu.:359260   3rd Qu.: 88576   3rd Qu.:1.0000  
##  Max.   :1.0415   Max.   :713000   Max.   :174621   Max.   :1.0000  
##  NA's   :1        NA's   :137      NA's   :137                      
##     male_sex         rec_age       race_2          race_1         
##  Min.   :0.0000   Min.   :27   Min.   :0.0000   Length:180        
##  1st Qu.:0.0000   1st Qu.:45   1st Qu.:0.0000   Class :character  
##  Median :1.0000   Median :54   Median :0.0000   Mode  :character  
##  Mean   :0.6167   Mean   :53   Mean   :0.4111                     
##  3rd Qu.:1.0000   3rd Qu.:61   3rd Qu.:1.0000                     
##  Max.   :1.0000   Max.   :73   Max.   :1.0000                     
##                                                                   
##   ethnicity         CKD_cause_1         CKD_cause_2      RRT_preTx     
##  Length:180         Length:180         Min.   :1.000   Min.   :0.0000  
##  Class :character   Class :character   1st Qu.:1.750   1st Qu.:1.0000  
##  Mode  :character   Mode  :character   Median :3.000   Median :1.0000  
##                                        Mean   :2.556   Mean   :0.9167  
##                                        3rd Qu.:3.000   3rd Qu.:1.0000  
##                                        Max.   :5.000   Max.   :1.0000  
##                                                                        
##    RRT_months        RRT_type      dc_graftloss_event_24mo
##  Min.   :  2.00   Min.   :0.0000   Min.   :0.00000        
##  1st Qu.: 36.00   1st Qu.:1.0000   1st Qu.:0.00000        
##  Median : 62.00   Median :1.0000   Median :0.00000        
##  Mean   : 73.55   Mean   :0.8121   Mean   :0.03333        
##  3rd Qu.: 96.00   3rd Qu.:1.0000   3rd Qu.:0.00000        
##  Max.   :288.00   Max.   :1.0000   Max.   :1.00000        
##  NA's   :15       NA's   :15                              
##  dc_graftloss_time_24mo male_sex_donor   age_donor     race_donor_2   
##  Min.   :  0.0          Min.   :0.00   Min.   : 4.0   Min.   :0.0000  
##  1st Qu.:730.0          1st Qu.:0.00   1st Qu.:31.5   1st Qu.:0.0000  
##  Median :730.0          Median :1.00   Median :42.0   Median :1.0000  
##  Mean   :652.7          Mean   :0.55   Mean   :40.3   Mean   :0.6167  
##  3rd Qu.:730.0          3rd Qu.:1.00   3rd Qu.:50.0   3rd Qu.:1.0000  
##  Max.   :730.0          Max.   :1.00   Max.   :69.0   Max.   :1.0000  
##                                        NA's   :1                      
##  race_donor_1       ethnicity_donor    donor_cause_broad  donor_cause_narrow
##  Length:180         Length:180         Length:180         Length:180        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  donor_cause_anoxia donor_cause_CVA    donor_type        ATG        
##  Min.   :0.0000     Min.   :0.0000   Min.   :0.00   Min.   :0.0000  
##  1st Qu.:0.0000     1st Qu.:0.0000   1st Qu.:0.75   1st Qu.:1.0000  
##  Median :0.0000     Median :0.0000   Median :1.00   Median :1.0000  
##  Mean   :0.4556     Mean   :0.2389   Mean   :0.75   Mean   :0.9944  
##  3rd Qu.:1.0000     3rd Qu.:0.0000   3rd Qu.:1.00   3rd Qu.:1.0000  
##  Max.   :1.0000     Max.   :1.0000   Max.   :1.00   Max.   :1.0000  
##                                                                     
##  maintenance_1      standard_triple      HLA_MM         HLAMMGE3       EBV_IgG 
##  Length:180         Min.   :0.0000   Min.   :0.000   Min.   :0.00   Min.   :1  
##  Class :character   1st Qu.:1.0000   1st Qu.:4.000   1st Qu.:1.00   1st Qu.:1  
##  Mode  :character   Median :1.0000   Median :5.000   Median :1.00   Median :1  
##                     Mean   :0.8889   Mean   :4.368   Mean   :0.85   Mean   :1  
##                     3rd Qu.:1.0000   3rd Qu.:5.000   3rd Qu.:1.00   3rd Qu.:1  
##                     Max.   :1.0000   Max.   :6.000   Max.   :1.00   Max.   :1  
##                                      NA's   :36                                
##   CMV_IgG_rec     CMV_IgG_donor     CMV_mismatch    CMV_mismatch_orig 
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Length:180        
##  1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   Class :character  
##  Median :1.0000   Median :1.0000   Median :0.0000   Mode  :character  
##  Mean   :0.6611   Mean   :0.5754   Mean   :0.1899                     
##  3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:0.0000                     
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000                     
##                   NA's   :1        NA's   :1                          
##  blood_group_rec    blood_group_donor      DRH                 KDPI      
##  Length:180         Length:180         Length:180         Min.   :20.00  
##  Class :character   Class :character   Class :character   1st Qu.:36.75  
##  Mode  :character   Mode  :character   Mode  :character   Median :53.00  
##                                                           Mean   :53.73  
##                                                           3rd Qu.:71.25  
##                                                           Max.   :93.00  
##                                                                          
##       WIT              CIT         perfusion_event  perfusion_time
##  Min.   :  0.00   Min.   : 3.267   Min.   :0.0000   Min.   : 2.0  
##  1st Qu.: 27.00   1st Qu.:10.267   1st Qu.:0.0000   1st Qu.: 8.0  
##  Median : 33.00   Median :15.367   Median :0.0000   Median :11.0  
##  Mean   : 37.02   Mean   :15.922   Mean   :0.3962   Mean   :11.3  
##  3rd Qu.: 42.00   3rd Qu.:20.550   3rd Qu.:1.0000   3rd Qu.:15.0  
##  Max.   :209.00   Max.   :50.133   Max.   :1.0000   Max.   :19.0  
##  NA's   :7        NA's   :3        NA's   :21       NA's   :147   
##  resistance_index TCMR_6mo_event    TCMR_6mo_time   TCMRB_6mo_event 
##  Min.   :0.0000   Min.   :0.00000   Min.   : 63.0   Min.   :0.0000  
##  1st Qu.:0.1500   1st Qu.:0.00000   1st Qu.:180.0   1st Qu.:0.0000  
##  Median :0.2050   Median :0.00000   Median :180.0   Median :0.0000  
##  Mean   :0.2125   Mean   :0.04386   Mean   :175.3   Mean   :0.1754  
##  3rd Qu.:0.2525   3rd Qu.:0.00000   3rd Qu.:180.0   3rd Qu.:0.0000  
##  Max.   :0.7000   Max.   :1.00000   Max.   :180.0   Max.   :1.0000  
##  NA's   :132      NA's   :66        NA's   :66      NA's   :66      
##  TCMRB_6mo_time  TCMR_24mo_event   TCMR_24mo_time TCMRB_24mo_event
##  Min.   : 11.0   Min.   :0.00000   Min.   : 63    Min.   :0.0000  
##  1st Qu.:180.0   1st Qu.:0.00000   1st Qu.:730    1st Qu.:0.0000  
##  Median :180.0   Median :0.00000   Median :730    Median :0.0000  
##  Mean   :161.6   Mean   :0.08943   Mean   :645    Mean   :0.2764  
##  3rd Qu.:180.0   3rd Qu.:0.00000   3rd Qu.:730    3rd Qu.:1.0000  
##  Max.   :183.0   Max.   :1.00000   Max.   :730    Max.   :1.0000  
##  NA's   :66      NA's   :57        NA's   :57     NA's   :57      
##  TCMRB_24mo_time AMR_6mo_event      AMR_6mo_time   AMR_24mo_event   
##  Min.   : 11.0   Min.   :0.00000   Min.   : 41.0   Min.   :0.00000  
##  1st Qu.:370.5   1st Qu.:0.00000   1st Qu.:180.0   1st Qu.:0.00000  
##  Median :730.0   Median :0.00000   Median :180.0   Median :0.00000  
##  Mean   :559.0   Mean   :0.02632   Mean   :175.9   Mean   :0.05691  
##  3rd Qu.:730.0   3rd Qu.:0.00000   3rd Qu.:180.0   3rd Qu.:0.00000  
##  Max.   :749.0   Max.   :1.00000   Max.   :180.0   Max.   :1.00000  
##  NA's   :57      NA's   :66        NA's   :66      NA's   :57       
##  AMR_24mo_time rejection_6mo_central rejectionB_6mo_central
##  Min.   : 41   Min.   :0.00000       Min.   :0.00000       
##  1st Qu.:730   1st Qu.:0.00000       1st Qu.:0.00000       
##  Median :730   Median :0.00000       Median :0.00000       
##  Mean   :668   Mean   :0.02703       Mean   :0.07207       
##  3rd Qu.:730   3rd Qu.:0.00000       3rd Qu.:0.00000       
##  Max.   :738   Max.   :1.00000       Max.   :1.00000       
##  NA's   :57    NA's   :69            NA's   :69            
##  rejection_24mo_central rejectionB_24mo_central CKD_EPI_3_vs_24  
##  Min.   :0.00000        Min.   :0.0000          Min.   :-35.490  
##  1st Qu.:0.00000        1st Qu.:0.0000          1st Qu.: -3.800  
##  Median :0.00000        Median :0.0000          Median :  1.330  
##  Mean   :0.03361        Mean   :0.1092          Mean   :  3.256  
##  3rd Qu.:0.00000        3rd Qu.:0.0000          3rd Qu.: 12.520  
##  Max.   :1.00000        Max.   :1.0000          Max.   : 50.760  
##  NA's   :61             NA's   :61              NA's   :91       
##  CKD_EPI_6_vs_24        DGF         CRR_day_2       CRR_below_30_day_2
##  Min.   :-35.810   Min.   :0.00   Min.   :-24.200   Min.   :0.0000    
##  1st Qu.: -3.250   1st Qu.:0.00   1st Qu.:  5.688   1st Qu.:0.0000    
##  Median :  2.805   Median :0.00   Median : 21.650   Median :1.0000    
##  Mean   :  2.925   Mean   :0.35   Mean   : 19.867   Mean   :0.6842    
##  3rd Qu.: 10.967   3rd Qu.:1.00   3rd Qu.: 33.292   3rd Qu.:1.0000    
##  Max.   : 38.160   Max.   :1.00   Max.   : 60.870   Max.   :1.0000    
##  NA's   :94                       NA's   :66        NA's   :66        
##    CRR_day_5      CRR_below_70_day_5 preformed_DSA      de_novo_DSA    
##  Min.   :-43.44   Min.   :0.0000     Min.   :0.00000   Min.   :0.0000  
##  1st Qu.: 30.08   1st Qu.:1.0000     1st Qu.:0.00000   1st Qu.:0.0000  
##  Median : 47.32   Median :1.0000     Median :0.00000   Median :0.0000  
##  Mean   : 42.78   Mean   :0.8333     Mean   :0.02809   Mean   :0.0618  
##  3rd Qu.: 63.48   3rd Qu.:1.0000     3rd Qu.:0.00000   3rd Qu.:0.0000  
##  Max.   : 84.22   Max.   :1.0000     Max.   :1.00000   Max.   :1.0000  
##  NA's   :66       NA's   :66         NA's   :2         NA's   :2       
##  infection_any    infection_wo_BKV infection_with_BKV infection_with_BKV_2
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000     Min.   :0.0000      
##  1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000     1st Qu.:0.0000      
##  Median :0.0000   Median :0.0000   Median :1.0000     Median :1.0000      
##  Mean   :0.4278   Mean   :0.3056   Mean   :0.5222     Mean   :0.5222      
##  3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.0000     3rd Qu.:1.0000      
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000     Max.   :1.0000      
##                                                                           
##   BKV_event_2     BKV_viremia_event BKV_viremia_time terminated_event
##  Min.   :0.0000   Min.   :0.0000    Min.   :   0.0   Min.   :0.0000  
##  1st Qu.:0.0000   1st Qu.:0.0000    1st Qu.: 188.8   1st Qu.:0.0000  
##  Median :0.0000   Median :0.0000    Median : 735.0   Median :0.0000  
##  Mean   :0.2167   Mean   :0.2167    Mean   : 684.0   Mean   :0.1889  
##  3rd Qu.:0.0000   3rd Qu.:0.0000    3rd Qu.: 939.2   3rd Qu.:0.0000  
##  Max.   :1.0000   Max.   :1.0000    Max.   :1854.0   Max.   :1.0000  
##                                                                      
##  terminated_days   death_event        death_date      death_time   
##  Min.   :   0.0   Min.   :0.00000   Min.   :43181   Min.   :  6.0  
##  1st Qu.: 121.2   1st Qu.:0.00000   1st Qu.:43370   1st Qu.:295.0  
##  Median : 258.5   Median :0.00000   Median :43425   Median :421.0  
##  Mean   : 373.4   Mean   :0.03333   Mean   :43428   Mean   :376.3  
##  3rd Qu.: 561.2   3rd Qu.:0.00000   3rd Qu.:43552   3rd Qu.:518.5  
##  Max.   :1323.0   Max.   :1.00000   Max.   :43591   Max.   :606.0  
##  NA's   :146                        NA's   :174     NA's   :174    
##  death_time_730  death_cause          death_24mo         GFR_days    
##  Min.   :  0.0   Length:180         Min.   :0.00000   Min.   : 26.0  
##  1st Qu.:730.0   Class :character   1st Qu.:0.00000   1st Qu.:369.2  
##  Median :730.0   Mode  :character   Median :0.00000   Median :692.5  
##  Mean   :656.8                      Mean   :0.03333   Mean   :542.4  
##  3rd Qu.:730.0                      3rd Qu.:0.00000   3rd Qu.:740.8  
##  Max.   :730.0                      Max.   :1.00000   Max.   :919.0  
##                                                       NA's   :2      
##     GFR_MDRD         GFR_CKD        GPE_dep_log2      MPE_dep_log2     
##  Min.   :  8.44   Min.   :  8.88   Min.   :-3.6439   Min.   :-3.60823  
##  1st Qu.: 39.08   1st Qu.: 38.17   1st Qu.:-2.6758   1st Qu.:-2.93237  
##  Median : 50.00   Median : 51.65   Median :-2.3921   Median :-2.45799  
##  Mean   : 51.91   Mean   : 54.26   Mean   :-2.2846   Mean   :-2.40078  
##  3rd Qu.: 64.56   3rd Qu.: 66.01   3rd Qu.:-2.0043   3rd Qu.:-1.99712  
##  Max.   :123.48   Max.   :106.01   Max.   : 0.4163   Max.   : 0.05866  
##  NA's   :2        NA's   :2        NA's   :1         NA's   :1         
##   GPE_ind_log2       MPE_ind_log2      GPL_BC_log2       MPL_BC_log2    
##  Min.   :-3.86775   Min.   :-3.8997   Min.   :-3.8616   Min.   :-5.533  
##  1st Qu.:-3.41120   1st Qu.:-3.4462   1st Qu.:-0.7257   1st Qu.: 1.097  
##  Median :-3.16488   Median :-3.1520   Median :-0.1035   Median : 2.029  
##  Mean   :-2.92959   Mean   :-3.0281   Mean   : 0.1137   Mean   : 1.999  
##  3rd Qu.:-2.71076   3rd Qu.:-2.7013   3rd Qu.: 0.8403   3rd Qu.: 2.958  
##  Max.   :-0.03283   Max.   :-0.5724   Max.   : 4.9498   Max.   : 5.417  
##  NA's   :1          NA's   :1                                           
##  treatment_group   
##  Length:180        
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 

skim(data2)
Data summary
Name data2
Number of rows 180
Number of columns 108
_______________________
Column type frequency:
character 15
numeric 93
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
ID_sample 0 1.00 3 5 0 180 0
race_1 0 1.00 5 41 0 6 0
ethnicity 0 1.00 18 22 0 2 0
CKD_cause_1 0 1.00 8 57 0 34 0
race_donor_1 0 1.00 5 41 0 6 0
ethnicity_donor 0 1.00 7 22 0 4 0
donor_cause_broad 0 1.00 3 50 0 36 0
donor_cause_narrow 0 1.00 5 24 0 9 0
maintenance_1 0 1.00 18 173 0 22 0
CMV_mismatch_orig 0 1.00 5 7 0 5 0
blood_group_rec 0 1.00 1 2 0 4 0
blood_group_donor 0 1.00 1 2 0 4 0
DRH 0 1.00 8 12 0 3 0
death_cause 174 0.03 8 192 0 6 0
treatment_group 0 1.00 7 9 0 2 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
ID_subject 0 1.00 17826.56 17534.06 1001.00 5016.75 8057.00 23007.25 57019.00 ▇▂▁▁▂
TNFR1_stain 156 0.13 1.67 0.56 0.00 1.00 2.00 2.00 2.00 ▁▁▃▁▇
TNFR2_stain 156 0.13 0.17 0.48 0.00 0.00 0.00 0.00 2.00 ▇▁▁▁▁
available 0 1.00 1.00 0.00 1.00 1.00 1.00 1.00 1.00 ▁▁▇▁▁
flow 137 0.24 1.00 0.00 1.00 1.00 1.00 1.00 1.00 ▁▁▇▁▁
GPL 0 1.00 1.91 3.31 0.13 0.63 0.94 1.74 30.76 ▇▁▁▁▁
MPL 0 1.00 6.74 7.48 0.75 2.35 4.13 7.41 41.37 ▇▁▁▁▁
GPL_BC 0 1.00 1.91 3.34 0.07 0.60 0.93 1.79 30.91 ▇▁▁▁▁
MPL_BC 0 1.00 6.64 7.69 0.02 2.14 4.08 7.77 42.72 ▇▂▁▁▁
GPE_ind 1 0.99 0.16 0.14 0.07 0.09 0.11 0.15 0.98 ▇▁▁▁▁
MPE_ind 1 0.99 0.13 0.08 0.07 0.09 0.11 0.15 0.67 ▇▁▁▁▁
GPE_dep 1 0.99 0.23 0.15 0.08 0.16 0.19 0.25 1.33 ▇▁▁▁▁
MPE_dep 1 0.99 0.21 0.12 0.08 0.13 0.18 0.25 1.04 ▇▂▁▁▁
flow_IgM 137 0.24 284641.16 143666.42 87937.00 172979.00 241051.00 359260.00 713000.00 ▇▃▃▂▁
flow_IgG 137 0.24 76880.23 24252.75 46682.00 60076.00 74844.00 88575.50 174621.00 ▇▇▂▁▁
infliximab 0 1.00 0.49 0.50 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▇
male_sex 0 1.00 0.62 0.49 0.00 0.00 1.00 1.00 1.00 ▅▁▁▁▇
rec_age 0 1.00 53.00 10.53 27.00 45.00 54.00 61.00 73.00 ▂▅▆▇▅
race_2 0 1.00 0.41 0.49 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▆
CKD_cause_2 0 1.00 2.56 1.23 1.00 1.75 3.00 3.00 5.00 ▆▆▇▂▂
RRT_preTx 0 1.00 0.92 0.28 0.00 1.00 1.00 1.00 1.00 ▁▁▁▁▇
RRT_months 15 0.92 73.55 50.47 2.00 36.00 62.00 96.00 288.00 ▇▇▂▁▁
RRT_type 15 0.92 0.81 0.39 0.00 1.00 1.00 1.00 1.00 ▂▁▁▁▇
dc_graftloss_event_24mo 0 1.00 0.03 0.18 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
dc_graftloss_time_24mo 0 1.00 652.68 189.67 0.00 730.00 730.00 730.00 730.00 ▁▁▁▁▇
male_sex_donor 0 1.00 0.55 0.50 0.00 0.00 1.00 1.00 1.00 ▆▁▁▁▇
age_donor 1 0.99 40.30 14.25 4.00 31.50 42.00 50.00 69.00 ▂▃▇▇▃
race_donor_2 0 1.00 0.62 0.49 0.00 0.00 1.00 1.00 1.00 ▅▁▁▁▇
donor_cause_anoxia 0 1.00 0.46 0.50 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▇
donor_cause_CVA 0 1.00 0.24 0.43 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
donor_type 0 1.00 0.75 0.43 0.00 0.75 1.00 1.00 1.00 ▂▁▁▁▇
ATG 0 1.00 0.99 0.07 0.00 1.00 1.00 1.00 1.00 ▁▁▁▁▇
standard_triple 0 1.00 0.89 0.32 0.00 1.00 1.00 1.00 1.00 ▁▁▁▁▇
HLA_MM 36 0.80 4.37 1.44 0.00 4.00 5.00 5.00 6.00 ▁▁▂▃▇
HLAMMGE3 0 1.00 0.85 0.36 0.00 1.00 1.00 1.00 1.00 ▂▁▁▁▇
EBV_IgG 0 1.00 1.00 0.00 1.00 1.00 1.00 1.00 1.00 ▁▁▇▁▁
CMV_IgG_rec 0 1.00 0.66 0.47 0.00 0.00 1.00 1.00 1.00 ▅▁▁▁▇
CMV_IgG_donor 1 0.99 0.58 0.50 0.00 0.00 1.00 1.00 1.00 ▆▁▁▁▇
CMV_mismatch 1 0.99 0.19 0.39 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
KDPI 0 1.00 53.73 20.62 20.00 36.75 53.00 71.25 93.00 ▇▇▆▆▅
WIT 7 0.96 37.02 21.46 0.00 27.00 33.00 42.00 209.00 ▇▂▁▁▁
CIT 3 0.98 15.92 7.17 3.27 10.27 15.37 20.55 50.13 ▆▇▃▁▁
perfusion_event 21 0.88 0.40 0.49 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▅
perfusion_time 147 0.18 11.30 4.88 2.00 8.00 11.00 15.00 19.00 ▅▃▇▅▇
resistance_index 132 0.27 0.21 0.11 0.00 0.15 0.21 0.25 0.70 ▂▇▂▁▁
TCMR_6mo_event 66 0.63 0.04 0.21 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
TCMR_6mo_time 66 0.63 175.32 20.14 63.00 180.00 180.00 180.00 180.00 ▁▁▁▁▇
TCMRB_6mo_event 66 0.63 0.18 0.38 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
TCMRB_6mo_time 66 0.63 161.62 42.27 11.00 180.00 180.00 180.00 183.00 ▁▁▁▁▇
TCMR_24mo_event 57 0.68 0.09 0.29 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
TCMR_24mo_time 57 0.68 644.98 192.07 63.00 730.00 730.00 730.00 730.00 ▁▁▁▁▇
TCMRB_24mo_event 57 0.68 0.28 0.45 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▃
TCMRB_24mo_time 57 0.68 558.97 262.62 11.00 370.50 730.00 730.00 749.00 ▂▁▁▁▇
AMR_6mo_event 66 0.63 0.03 0.16 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
AMR_6mo_time 66 0.63 175.88 21.10 41.00 180.00 180.00 180.00 180.00 ▁▁▁▁▇
AMR_24mo_event 57 0.68 0.06 0.23 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
AMR_24mo_time 57 0.68 667.95 166.15 41.00 730.00 730.00 730.00 738.00 ▁▁▁▁▇
rejection_6mo_central 69 0.62 0.03 0.16 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
rejectionB_6mo_central 69 0.62 0.07 0.26 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
rejection_24mo_central 61 0.66 0.03 0.18 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
rejectionB_24mo_central 61 0.66 0.11 0.31 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
CKD_EPI_3_vs_24 91 0.49 3.26 14.66 -35.49 -3.80 1.33 12.52 50.76 ▁▆▇▃▁
CKD_EPI_6_vs_24 94 0.48 2.92 12.16 -35.81 -3.25 2.80 10.97 38.16 ▁▂▇▃▁
DGF 0 1.00 0.35 0.48 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▅
CRR_day_2 66 0.63 19.87 20.13 -24.20 5.69 21.65 33.29 60.87 ▃▅▇▇▃
CRR_below_30_day_2 66 0.63 0.68 0.47 0.00 0.00 1.00 1.00 1.00 ▃▁▁▁▇
CRR_day_5 66 0.63 42.78 28.23 -43.44 30.08 47.32 63.48 84.22 ▁▂▃▇▇
CRR_below_70_day_5 66 0.63 0.83 0.37 0.00 1.00 1.00 1.00 1.00 ▂▁▁▁▇
preformed_DSA 2 0.99 0.03 0.17 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
de_novo_DSA 2 0.99 0.06 0.24 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
infection_any 0 1.00 0.43 0.50 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▆
infection_wo_BKV 0 1.00 0.31 0.46 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▃
infection_with_BKV 0 1.00 0.52 0.50 0.00 0.00 1.00 1.00 1.00 ▇▁▁▁▇
infection_with_BKV_2 0 1.00 0.52 0.50 0.00 0.00 1.00 1.00 1.00 ▇▁▁▁▇
BKV_event_2 0 1.00 0.22 0.41 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
BKV_viremia_event 0 1.00 0.22 0.41 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
BKV_viremia_time 0 1.00 684.03 473.89 0.00 188.75 735.00 939.25 1854.00 ▇▅▆▃▁
terminated_event 0 1.00 0.19 0.39 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
terminated_days 146 0.19 373.41 316.48 0.00 121.25 258.50 561.25 1323.00 ▇▂▃▁▁
death_event 0 1.00 0.03 0.18 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
death_date 174 0.03 43428.17 153.81 43181.00 43370.50 43425.00 43552.25 43591.00 ▃▁▇▃▇
death_time 174 0.03 376.33 217.96 6.00 295.00 421.00 518.50 606.00 ▃▁▃▇▇
death_time_730 0 1.00 656.81 186.21 0.00 730.00 730.00 730.00 730.00 ▁▁▁▁▇
death_24mo 0 1.00 0.03 0.18 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
GFR_days 2 0.99 542.43 248.23 26.00 369.25 692.50 740.75 919.00 ▅▃▃▇▇
GFR_MDRD 2 0.99 51.91 20.20 8.44 39.08 50.00 64.56 123.48 ▃▇▆▂▁
GFR_CKD 2 0.99 54.26 22.33 8.88 38.17 51.65 66.01 106.01 ▂▇▇▃▂
GPE_dep_log2 1 0.99 -2.28 0.66 -3.64 -2.68 -2.39 -2.00 0.42 ▂▇▂▁▁
MPE_dep_log2 1 0.99 -2.40 0.67 -3.61 -2.93 -2.46 -2.00 0.06 ▆▇▆▁▁
GPE_ind_log2 1 0.99 -2.93 0.73 -3.87 -3.41 -3.16 -2.71 -0.03 ▇▅▁▁▁
MPE_ind_log2 1 0.99 -3.03 0.57 -3.90 -3.45 -3.15 -2.70 -0.57 ▇▇▃▁▁
GPL_BC_log2 0 1.00 0.11 1.41 -3.86 -0.73 -0.10 0.84 4.95 ▁▇▇▃▁
MPL_BC_log2 0 1.00 2.00 1.55 -5.53 1.10 2.03 2.96 5.42 ▁▁▃▇▃

There are two variables that are expected to affect the outcomes but include many missing values. Look which variables are correlated with these variables (perfusion_event and HLA_MM) so these may be helpful for the imputation.

Open code
safe_cor <- function(x, y) {
  if (sd(x, na.rm = TRUE) == 0 || sd(y, na.rm = TRUE) == 0) {
    NA_real_
  } else {
    cor(x, y, use = "pairwise.complete.obs", method = 'pearson')
  }
}

df <- data2 %>%
  select(where(is.numeric))

res <- tibble(
  variable       = names(df),
  cor_perfusion  = map_dbl(variable, ~ safe_cor(df[[.x]], df$perfusion_event)),
  cor_hla        = map_dbl(variable, ~ safe_cor(df[[.x]], df$HLA_MM)),
  n_na           = map_int(variable, ~ sum(is.na(df[[.x]])))
) %>%
  mutate(max_abs_cor = pmax(abs(cor_perfusion), abs(cor_hla), na.rm = TRUE)) %>%
  arrange(desc(max_abs_cor))
## Warning in cor(x, y, use = "pairwise.complete.obs", method = "pearson"): the
## standard deviation is zero
## Warning in cor(x, y, use = "pairwise.complete.obs", method = "pearson"): the
## standard deviation is zero
## Warning in cor(x, y, use = "pairwise.complete.obs", method = "pearson"): the
## standard deviation is zero

kableExtra::kable(res %>% filter(n_na<10, max_abs_cor>0.1))
variable cor_perfusion cor_hla n_na max_abs_cor
HLAMMGE3 0.1521796 0.7388502 0 0.7388502
BKV_viremia_time 0.2740103 -0.0162880 0 0.2740103
GFR_CKD -0.1605158 -0.2709311 2 0.2709311
race_2 0.2353864 -0.1944819 0 0.2353864
GFR_MDRD -0.1685550 -0.2334869 2 0.2334869
GPE_ind 0.2170082 0.0316690 1 0.2170082
race_donor_2 0.2131970 -0.0264465 0 0.2131970
age_donor 0.1486748 0.1994518 1 0.1994518
CIT 0.1903365 -0.1393050 3 0.1903365
CMV_IgG_rec -0.0818317 0.1860303 0 0.1860303
de_novo_DSA 0.0807407 0.1769103 2 0.1769103
KDPI 0.0744357 0.1750746 0 0.1750746
donor_type -0.1691540 0.0328450 0 0.1691540
GPE_ind_log2 0.1687633 0.0447728 1 0.1687633
ID_subject 0.1620089 -0.1226652 0 0.1620089
MPE_dep -0.1584339 0.0166590 1 0.1584339
MPL_BC -0.1555197 -0.0622218 0 0.1555197
MPL_BC_log2 -0.1518460 -0.0367600 0 0.1518460
GPL_BC_log2 -0.1480250 -0.1102327 0 0.1480250
RRT_preTx -0.0024901 -0.1451204 0 0.1451204
MPE_dep_log2 -0.1448089 0.0124194 1 0.1448089
GPL_BC -0.1132365 -0.1437448 0 0.1437448
CMV_IgG_donor 0.0710178 0.1437226 1 0.1437226
GPL -0.1130782 -0.1432358 0 0.1432358
male_sex 0.1431312 0.0824554 0 0.1431312
MPL -0.1421092 -0.0587360 0 0.1421092
WIT 0.1409576 -0.0638921 7 0.1409576
DGF -0.0424969 0.1340953 0 0.1340953
male_sex_donor -0.0485702 -0.1333746 0 0.1333746
dc_graftloss_event_24mo -0.1301364 -0.0487302 0 0.1301364
infliximab 0.0591993 0.1247757 0 0.1247757
MPE_ind -0.1246244 -0.0598818 1 0.1246244
GFR_days 0.1222818 0.0609560 2 0.1222818
rec_age -0.0243711 0.1218259 0 0.1218259
preformed_DSA -0.1142633 -0.0309393 2 0.1142633
MPE_ind_log2 -0.1014825 -0.0061797 1 0.1014825

3.1 Summary tables

Who will be deleted?

Open code
data2 %>% 
  filter(is.na(GFR_MDRD) |
         is.na(GPE_dep) |
         is.na(MPE_dep) 
         ) %>%  select(ID_subject)
##   ID_subject
## 1       3027
## 2      23007
## 3      57019

3.1.1 Demography

Open code
data2 %>% 
  filter(!is.na(GFR_MDRD),
         !is.na(GPE_dep),
         !is.na(MPE_dep)) %>% 
  select(male_sex, rec_age, race_2, race_1, ethnicity, treatment_group, CKD_cause_2, RRT_preTx, RRT_months, RRT_type, male_sex_donor, age_donor, race_donor_2, race_donor_1, donor_cause_narrow, donor_cause_anoxia, donor_cause_CVA, donor_type, ATG, standard_triple, HLA_MM, KDPI, WIT, CIT, perfusion_event, perfusion_time, preformed_DSA) %>% 
  tbl_summary(by = treatment_group, type = list(HLA_MM ~ "continuous")) %>% 
  add_p() %>% 
  add_overall()
## The following warnings were returned during `add_p()`:
## ! For variable `perfusion_time` (`treatment_group`) and "estimate",
##   "statistic", "p.value", "conf.low", and "conf.high" statistics: cannot
##   compute exact p-value with ties
## ! For variable `perfusion_time` (`treatment_group`) and "estimate",
##   "statistic", "p.value", "conf.low", and "conf.high" statistics: cannot
##   compute exact confidence intervals with ties
Table 1: Demography stratified by treatment

Characteristic

Overall
N = 177

1

infiximab
N = 87

1

placebo
N = 90

1

p-value

2
male_sex 109 (62%) 59 (68%) 50 (56%) 0.094
rec_age 54 (45, 61) 54 (46, 61) 55 (45, 62) >0.9
race_2 72 (41%) 35 (40%) 37 (41%) >0.9
race_1


0.9
    American Indian or Alaska Native 1 (0.6%) 1 (1.1%) 0 (0%)
    Asian 9 (5.1%) 5 (5.7%) 4 (4.4%)
    Black or African American 73 (41%) 34 (39%) 39 (43%)
    Native Hawaiian or Other Pacific Islander 3 (1.7%) 1 (1.1%) 2 (2.2%)
    Unknown or Not Reported 19 (11%) 11 (13%) 8 (8.9%)
    White 72 (41%) 35 (40%) 37 (41%)
ethnicity


0.2
    Hispanic or Latino 25 (14%) 15 (17%) 10 (11%)
    Not Hispanic or Latino 152 (86%) 72 (83%) 80 (89%)
CKD_cause_2


0.3
    1 44 (25%) 23 (26%) 21 (23%)
    2 42 (24%) 22 (25%) 20 (22%)
    3 58 (33%) 27 (31%) 31 (34%)
    4 18 (10%) 11 (13%) 7 (7.8%)
    5 15 (8.5%) 4 (4.6%) 11 (12%)
RRT_preTx 162 (92%) 80 (92%) 82 (91%) 0.8
RRT_months 62 (36, 95) 63 (37, 92) 62 (36, 96) >0.9
    Unknown 15 7 8
RRT_type 132 (81%) 64 (80%) 68 (83%) 0.6
    Unknown 15 7 8
male_sex_donor 98 (55%) 43 (49%) 55 (61%) 0.12
age_donor 43 (32, 50) 44 (32, 50) 42 (30, 50) 0.5
    Unknown 1 1 0
race_donor_2 109 (62%) 59 (68%) 50 (56%) 0.094
race_donor_1


0.033
    American Indian or Alaska Native 2 (1.1%) 0 (0%) 2 (2.2%)
    Asian 9 (5.1%) 2 (2.3%) 7 (7.8%)
    Black or African American 30 (17%) 10 (11%) 20 (22%)
    Native Hawaiian or Other Pacific Islander 1 (0.6%) 0 (0%) 1 (1.1%)
    Unknown or Not Reported 26 (15%) 16 (18%) 10 (11%)
    White 109 (62%) 59 (68%) 50 (56%)
donor_cause_narrow


>0.9
    Anoxia 82 (46%) 38 (44%) 44 (49%)
    Cardiovascular 5 (2.8%) 2 (2.3%) 3 (3.3%)
    Cerebrovascular Accident 42 (24%) 22 (25%) 20 (22%)
    CNS-Other 1 (0.6%) 0 (0%) 1 (1.1%)
    Drug Overdose 2 (1.1%) 1 (1.1%) 1 (1.1%)
    Head Trauma 38 (21%) 21 (24%) 17 (19%)
    Infection 2 (1.1%) 1 (1.1%) 1 (1.1%)
    Other 2 (1.1%) 1 (1.1%) 1 (1.1%)
    Respiratory Failure 3 (1.7%) 1 (1.1%) 2 (2.2%)
donor_cause_anoxia 82 (46%) 38 (44%) 44 (49%) 0.5
donor_cause_CVA 42 (24%) 22 (25%) 20 (22%) 0.6
donor_type 133 (75%) 64 (74%) 69 (77%) 0.6
ATG 176 (99%) 87 (100%) 89 (99%) >0.9
standard_triple 158 (89%) 76 (87%) 82 (91%) 0.4
HLA_MM 5.00 (4.00, 5.00) 5.00 (4.00, 6.00) 4.00 (3.50, 5.00) 0.080
    Unknown 35 17 18
KDPI 53 (37, 71) 53 (32, 71) 51 (39, 74) 0.4
WIT 33 (27, 42) 33 (27, 42) 33 (27, 40) 0.9
    Unknown 6 3 3
CIT 15 (10, 21) 16 (10, 21) 15 (10, 20) 0.8
    Unknown 3 3 0
perfusion_event 63 (40%) 34 (44%) 29 (37%) 0.4
    Unknown 21 9 12
perfusion_time 11.0 (8.0, 15.0) 12.0 (8.0, 15.0) 11.0 (6.0, 16.0) 0.5
    Unknown 144 68 76
preformed_DSA 5 (2.8%) 2 (2.3%) 3 (3.3%) >0.9
1

n (%); Median (Q1, Q3)

2

Pearson’s Chi-squared test; Wilcoxon rank sum test; Fisher’s exact test

3.1.2 Demography stratified treatment and aCL IgG groups

Open code
sum_data <- data2 %>%
  filter(!is.na(GFR_MDRD),
         !is.na(GPE_dep),
         !is.na(MPE_dep)) %>% 
  dplyr::select(
    DGF, infection_any, GFR_MDRD,  BKV_event_2,
    
    GPL_BC,
    MPL_BC,
    GPE_dep,
    GPE_ind,
    MPE_dep,
    MPE_ind,
    
    male_sex,
    HLA_MM,
    male_sex_donor,
    KDPI,
    perfusion_event,
    CIT,
    infliximab,
    rec_age,
    race_2, race_1, ethnicity, CKD_cause_2, RRT_preTx, RRT_months, RRT_type, age_donor, 
    race_donor_2, race_donor_1, donor_cause_narrow, donor_cause_anoxia, donor_cause_CVA, 
    donor_type, ATG, standard_triple, WIT, perfusion_event, perfusion_time, preformed_DSA) %>% 
  
  mutate(aCL_IgG_category = if_else(GPL_BC < median(data2$GPL_BC, na.rm =TRUE),
                                    'low aCL IgG', 'high aCL'
                                    ),
         treatment = if_else(infliximab == 1, 'IFX', 'PCO')
         ) %>% 
  mutate(category = interaction(treatment, aCL_IgG_category)) 

sum_data %>% select(-c(infliximab, aCL_IgG_category, GPL_BC:MPE_ind)) %>% 
  gtsummary::tbl_summary(by = category,
                         type = list(HLA_MM ~ "continuous")) %>% 
  add_p() %>% 
  add_overall()
## The following errors were returned during `add_p()`:
## ✖ For variable `CKD_cause_2` (`category`) and "estimate", "p.value",
##   "conf.low", and "conf.high" statistics: FEXACT error 7(location). LDSTP=18630
##   is too small for this problem, (pastp=85.2787, ipn_0:=ipoin[itp=620]=102,
##   stp[ipn_0]=84.8266). Increase workspace or consider using
##   'simulate.p.value=TRUE'
## ✖ For variable `donor_cause_narrow` (`category`) and "estimate", "p.value",
##   "conf.low", and "conf.high" statistics: FEXACT error 6.  LDKEY=621 is too
##   small for this problem, (ii := key2[itp=484] = 3638300, ldstp=18630) Try
##   increasing the size of the workspace and possibly 'mult'
## ✖ For variable `race_donor_1` (`category`) and "estimate", "p.value",
##   "conf.low", and "conf.high" statistics: FEXACT error 7(location). LDSTP=18630
##   is too small for this problem, (pastp=37.0568, ipn_0:=ipoin[itp=277]=2971,
##   stp[ipn_0]=36.487). Increase workspace or consider using
##   'simulate.p.value=TRUE'
Table 2: Demography stratified by treatment and aCL IgG level (below and at/above median value

Characteristic

Overall
N = 177

1

IFX.high aCL
N = 41

1

PCO.high aCL
N = 47

1

IFX.low aCL IgG
N = 46

1

PCO.low aCL IgG
N = 43

1

p-value

2
DGF 60 (34%) 19 (46%) 14 (30%) 9 (20%) 18 (42%) 0.035
infection_any 75 (42%) 17 (41%) 17 (36%) 21 (46%) 20 (47%) 0.7
GFR_MDRD 50 (39, 65) 45 (35, 51) 58 (44, 70) 56 (40, 68) 47 (35, 62) 0.029
BKV_event_2 38 (21%) 12 (29%) 5 (11%) 13 (28%) 8 (19%) 0.10
male_sex 109 (62%) 26 (63%) 26 (55%) 33 (72%) 24 (56%) 0.3
HLA_MM 5.00 (4.00, 5.00) 5.00 (4.00, 5.00) 4.50 (4.00, 5.00) 5.00 (4.00, 6.00) 4.00 (3.00, 5.50) 0.15
    Unknown 35 8 11 9 7
male_sex_donor 98 (55%) 19 (46%) 29 (62%) 24 (52%) 26 (60%) 0.4
KDPI 53 (37, 71) 49 (29, 66) 52 (37, 76) 54 (35, 72) 50 (39, 74) 0.6
perfusion_event 63 (40%) 15 (41%) 14 (32%) 19 (46%) 15 (44%) 0.5
    Unknown 21 4 3 5 9
CIT 15 (10, 21) 17 (10, 21) 16 (10, 22) 14 (10, 20) 14 (10, 20) 0.7
    Unknown 3 1 0 2 0
rec_age 54 (45, 61) 53 (45, 60) 55 (45, 61) 56 (48, 63) 54 (45, 63) 0.8
race_2 72 (41%) 16 (39%) 17 (36%) 19 (41%) 20 (47%) 0.8
race_1




0.8
    American Indian or Alaska Native 1 (0.6%) 0 (0%) 0 (0%) 1 (2.2%) 0 (0%)
    Asian 9 (5.1%) 1 (2.4%) 3 (6.4%) 4 (8.7%) 1 (2.3%)
    Black or African American 73 (41%) 18 (44%) 22 (47%) 16 (35%) 17 (40%)
    Native Hawaiian or Other Pacific Islander 3 (1.7%) 1 (2.4%) 0 (0%) 0 (0%) 2 (4.7%)
    Unknown or Not Reported 19 (11%) 5 (12%) 5 (11%) 6 (13%) 3 (7.0%)
    White 72 (41%) 16 (39%) 17 (36%) 19 (41%) 20 (47%)
ethnicity




0.4
    Hispanic or Latino 25 (14%) 8 (20%) 7 (15%) 7 (15%) 3 (7.0%)
    Not Hispanic or Latino 152 (86%) 33 (80%) 40 (85%) 39 (85%) 40 (93%)
CKD_cause_2





    1 44 (25%) 10 (24%) 11 (23%) 13 (28%) 10 (23%)
    2 42 (24%) 9 (22%) 9 (19%) 13 (28%) 11 (26%)
    3 58 (33%) 13 (32%) 15 (32%) 14 (30%) 16 (37%)
    4 18 (10%) 5 (12%) 5 (11%) 6 (13%) 2 (4.7%)
    5 15 (8.5%) 4 (9.8%) 7 (15%) 0 (0%) 4 (9.3%)
RRT_preTx 162 (92%) 41 (100%) 39 (83%) 39 (85%) 43 (100%) <0.001
RRT_months 62 (36, 95) 73 (49, 105) 60 (39, 83) 51 (36, 81) 65 (34, 115) 0.3
    Unknown 15 0 8 7 0
RRT_type 132 (81%) 37 (90%) 33 (85%) 27 (69%) 35 (81%) 0.10
    Unknown 15 0 8 7 0
age_donor 43 (32, 50) 38 (32, 48) 43 (24, 50) 45 (34, 50) 41 (32, 52) 0.7
    Unknown 1 0 0 1 0
race_donor_2 109 (62%) 28 (68%) 27 (57%) 31 (67%) 23 (53%) 0.4
race_donor_1





    American Indian or Alaska Native 2 (1.1%) 0 (0%) 1 (2.1%) 0 (0%) 1 (2.3%)
    Asian 9 (5.1%) 1 (2.4%) 3 (6.4%) 1 (2.2%) 4 (9.3%)
    Black or African American 30 (17%) 3 (7.3%) 9 (19%) 7 (15%) 11 (26%)
    Native Hawaiian or Other Pacific Islander 1 (0.6%) 0 (0%) 0 (0%) 0 (0%) 1 (2.3%)
    Unknown or Not Reported 26 (15%) 9 (22%) 7 (15%) 7 (15%) 3 (7.0%)
    White 109 (62%) 28 (68%) 27 (57%) 31 (67%) 23 (53%)
donor_cause_narrow





    Anoxia 82 (46%) 18 (44%) 24 (51%) 20 (43%) 20 (47%)
    Cardiovascular 5 (2.8%) 1 (2.4%) 2 (4.3%) 1 (2.2%) 1 (2.3%)
    Cerebrovascular Accident 42 (24%) 7 (17%) 10 (21%) 15 (33%) 10 (23%)
    CNS-Other 1 (0.6%) 0 (0%) 0 (0%) 0 (0%) 1 (2.3%)
    Drug Overdose 2 (1.1%) 0 (0%) 0 (0%) 1 (2.2%) 1 (2.3%)
    Head Trauma 38 (21%) 14 (34%) 8 (17%) 7 (15%) 9 (21%)
    Infection 2 (1.1%) 1 (2.4%) 1 (2.1%) 0 (0%) 0 (0%)
    Other 2 (1.1%) 0 (0%) 1 (2.1%) 1 (2.2%) 0 (0%)
    Respiratory Failure 3 (1.7%) 0 (0%) 1 (2.1%) 1 (2.2%) 1 (2.3%)
donor_cause_anoxia 82 (46%) 18 (44%) 24 (51%) 20 (43%) 20 (47%) 0.9
donor_cause_CVA 42 (24%) 7 (17%) 10 (21%) 15 (33%) 10 (23%) 0.4
donor_type 133 (75%) 27 (66%) 35 (74%) 37 (80%) 34 (79%) 0.4
ATG 176 (99%) 41 (100%) 47 (100%) 46 (100%) 42 (98%) 0.5
standard_triple 158 (89%) 34 (83%) 43 (91%) 42 (91%) 39 (91%) 0.6
WIT 33 (27, 42) 32 (25, 42) 32 (26, 38) 35 (28, 43) 37 (29, 47) 0.2
    Unknown 6 1 1 2 2
perfusion_time 11.0 (8.0, 15.0) 14.0 (12.0, 16.0) 16.0 (11.0, 16.0) 11.0 (5.0, 14.0) 8.0 (5.0, 11.0) 0.030
    Unknown 144 32 40 36 36
preformed_DSA 5 (2.8%) 2 (4.9%) 2 (4.3%) 0 (0%) 1 (2.3%) 0.5
treatment




<0.001
    IFX 87 (49%) 41 (100%) 0 (0%) 46 (100%) 0 (0%)
    PCO 90 (51%) 0 (0%) 47 (100%) 0 (0%) 43 (100%)
1

n (%); Median (Q1, Q3)

2

Pearson’s Chi-squared test; Kruskal-Wallis rank sum test; Fisher’s exact test

3.1.3 Outcomes by treatment arm

Open code
sum_data %>% select(treatment, DGF:BKV_event_2) %>% 
  gtsummary::tbl_summary(by = treatment) %>% 
  add_p() %>% 
  add_overall()
Table 3: Post-transplant outcomes by treatment

Characteristic

Overall
N = 177

1

IFX
N = 87

1

PCO
N = 90

1

p-value

2
DGF 60 (34%) 28 (32%) 32 (36%) 0.6
infection_any 75 (42%) 38 (44%) 37 (41%) 0.7
GFR_MDRD 50 (39, 65) 50 (39, 62) 51 (39, 66) 0.3
BKV_event_2 38 (21%) 25 (29%) 13 (14%) 0.021
1

n (%); Median (Q1, Q3)

2

Pearson’s Chi-squared test; Wilcoxon rank sum test

3.1.4 Antigens

3.1.4.1 In general

Open code
data2 %>%
  filter(
    !is.na(GFR_MDRD),
    !is.na(GPE_dep_log2),
    !is.na(MPE_dep_log2)
  ) %>%
  select(
    treatment_group,
    GPL_BC, MPL_BC, MPE_ind, MPE_dep, GPE_ind, GPE_dep
  ) %>%
  tbl_summary(by = treatment_group) %>%
  add_p() %>%
  add_overall()

Characteristic

Overall
N = 177

1

infiximab
N = 87

1

placebo
N = 90

1

p-value

2
GPL_BC 0.93 (0.60, 1.80) 0.87 (0.56, 1.55) 0.96 (0.65, 2.08) 0.3
MPL_BC 4 (2, 8) 3 (2, 6) 5 (2, 10) 0.005
MPE_ind 0.11 (0.09, 0.15) 0.11 (0.09, 0.15) 0.12 (0.09, 0.15) 0.6
MPE_dep 0.18 (0.13, 0.25) 0.18 (0.12, 0.25) 0.19 (0.14, 0.26) 0.4
GPE_ind 0.11 (0.09, 0.15) 0.12 (0.10, 0.15) 0.11 (0.09, 0.15) 0.7
GPE_dep 0.19 (0.16, 0.25) 0.19 (0.15, 0.26) 0.19 (0.16, 0.24) 0.3
1

Median (Q1, Q3)

2

Wilcoxon rank sum test

3.1.4.2 Only these with DGF

Open code
data2 %>% 
  filter(!is.na(GFR_MDRD),
         !is.na(GPE_dep_log2),
         !is.na(MPE_dep_log2)) %>% 
  filter(DGF == 1) %>% 
  select(treatment_group, 
         GPL_BC, MPL_BC, MPE_ind, MPE_dep, GPE_ind, GPE_dep) %>% 
  
  tbl_summary(by = treatment_group) %>% 
  add_p() %>% 
  add_overall()
## The following warnings were returned during `add_p()`:
## ! For variable `GPE_dep` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   p-value with ties
## ! For variable `GPE_dep` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   confidence intervals with ties
## ! For variable `GPE_ind` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   p-value with ties
## ! For variable `GPE_ind` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   confidence intervals with ties
## ! For variable `MPE_dep` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   p-value with ties
## ! For variable `MPE_dep` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   confidence intervals with ties
## ! For variable `MPE_ind` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   p-value with ties
## ! For variable `MPE_ind` (`treatment_group`) and "estimate", "statistic",
##   "p.value", "conf.low", and "conf.high" statistics: cannot compute exact
##   confidence intervals with ties

Characteristic

Overall
N = 60

1

infiximab
N = 28

1

placebo
N = 32

1

p-value

2
GPL_BC 0.96 (0.59, 2.55) 1.15 (0.75, 3.32) 0.80 (0.57, 1.87) 0.2
MPL_BC 6 (3, 9) 6 (3, 8) 6 (3, 12) 0.8
MPE_ind 0.11 (0.09, 0.15) 0.11 (0.09, 0.17) 0.11 (0.09, 0.14) >0.9
MPE_dep 0.17 (0.13, 0.25) 0.22 (0.14, 0.26) 0.16 (0.12, 0.25) 0.4
GPE_ind 0.12 (0.09, 0.15) 0.13 (0.10, 0.15) 0.11 (0.09, 0.15) 0.3
GPE_dep 0.20 (0.15, 0.28) 0.20 (0.16, 0.27) 0.18 (0.13, 0.30) 0.5
1

Median (Q1, Q3)

2

Wilcoxon rank sum exact test; Wilcoxon rank sum test

3.1.4.3 Only these without DGF

Open code
data2 %>% 
  filter(!is.na(GFR_MDRD),
         !is.na(GPE_dep_log2),
         !is.na(MPE_dep_log2)) %>% 
  filter(DGF == 0) %>% 
  select(treatment_group, 
         GPL_BC, MPL_BC, MPE_ind, MPE_dep, GPE_ind, GPE_dep) %>% 
  tbl_summary(by = treatment_group) %>% 
  add_p() %>% 
  add_overall()

Characteristic

Overall
N = 117

1

infiximab
N = 59

1

placebo
N = 58

1

p-value

2
GPL_BC 0.89 (0.61, 1.66) 0.79 (0.53, 1.28) 1.09 (0.70, 2.09) 0.018
MPL_BC 3.5 (2.0, 6.6) 2.6 (1.8, 4.7) 4.6 (2.5, 9.1) <0.001
MPE_ind 0.11 (0.09, 0.15) 0.11 (0.09, 0.15) 0.12 (0.09, 0.16) 0.5
MPE_dep 0.19 (0.13, 0.25) 0.17 (0.12, 0.23) 0.20 (0.15, 0.26) 0.072
GPE_ind 0.11 (0.09, 0.15) 0.11 (0.09, 0.15) 0.11 (0.10, 0.17) 0.8
GPE_dep 0.19 (0.16, 0.25) 0.19 (0.15, 0.26) 0.19 (0.16, 0.22) 0.6
1

Median (Q1, Q3)

2

Wilcoxon rank sum test

3.2 Antigens data distributions

Open code

data_hist <- data2 %>% 
  filter(!is.na(GFR_MDRD),
         !is.na(GPE_dep_log2),
         !is.na(MPE_dep_log2)) %>% 
  mutate(infliximab = if_else(infliximab == 1, 'IFX', 'PCO'))


p1 <- data_hist %>% 
  ggplot(aes(x = GPL_BC)) +
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p2 <- data_hist %>%
  ggplot(aes(x = GPL_BC_log2))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p3 <- data_hist %>%
  ggplot(aes(x = MPL_BC))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p4 <- data_hist %>%
  ggplot(aes(x = MPL_BC_log2))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p5 <- data_hist %>%
  ggplot(aes(x = MPE_ind))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p6 <- data_hist %>%
  ggplot(aes(x = MPE_ind_log2))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p7 <- data_hist %>%
  ggplot(aes(x = MPE_dep))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p8 <- data_hist %>%
  ggplot(aes(x = MPE_dep_log2))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p9 <- data_hist %>%
  ggplot(aes(x = GPE_ind))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p10 <- data_hist %>%
  ggplot(aes(x = GPE_ind_log2))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p11 <- data_hist %>%
  ggplot(aes(x = GPE_dep))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

p12 <- data_hist %>%
  ggplot(aes(x = GPE_dep_log2))+
  geom_histogram() +
  facet_wrap(~ infliximab, nrow = 2)

plot_grid(p1,p2,p3,p4, p5, p6, p7, p8, p9, p10, p11, p12, nrow = 3)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

4 Data - models-relevant

4.1 Define the model-relevant data

Open code
data_model_priorImpute <- data2 %>%
  dplyr::select(
    
    # outcomes 
    DGF, infection_any, GFR_MDRD,  BKV_event_2,
    
    # antigens
    GPL_BC_log2,
    MPL_BC_log2,
    GPE_dep_log2,
    GPE_ind_log2,
    MPE_dep_log2,
    MPE_ind_log2,
    
    # other covariates
    male_sex,
    HLA_MM,
    male_sex_donor,
    KDPI,
    perfusion_event,
    CIT,
    infliximab,
    rec_age,
    
    # variables for imputation only
    HLAMMGE3, 
    BKV_viremia_time,
    race_2,
    race_donor_2,
    age_donor,
    CMV_IgG_rec,
    de_novo_DSA,
    donor_type 
  ) %>% 
  filter(!is.na(GFR_MDRD),
         !is.na(GPE_dep_log2),
         !is.na(MPE_dep_log2))

data_model_priorImpute %>% summary()
##       DGF        infection_any       GFR_MDRD       BKV_event_2    
##  Min.   :0.000   Min.   :0.0000   Min.   :  8.44   Min.   :0.0000  
##  1st Qu.:0.000   1st Qu.:0.0000   1st Qu.: 39.07   1st Qu.:0.0000  
##  Median :0.000   Median :0.0000   Median : 49.88   Median :0.0000  
##  Mean   :0.339   Mean   :0.4237   Mean   : 51.90   Mean   :0.2147  
##  3rd Qu.:1.000   3rd Qu.:1.0000   3rd Qu.: 64.98   3rd Qu.:0.0000  
##  Max.   :1.000   Max.   :1.0000   Max.   :123.48   Max.   :1.0000  
##                                                                    
##   GPL_BC_log2       MPL_BC_log2      GPE_dep_log2      GPE_ind_log2     
##  Min.   :-3.8616   Min.   :-5.533   Min.   :-3.6439   Min.   :-3.86775  
##  1st Qu.:-0.7449   1st Qu.: 1.093   1st Qu.:-2.6666   1st Qu.:-3.41120  
##  Median :-0.1046   Median : 2.043   Median :-2.3921   Median :-3.16488  
##  Mean   : 0.1147   Mean   : 1.996   Mean   :-2.2821   Mean   :-2.92303  
##  3rd Qu.: 0.8505   3rd Qu.: 2.942   3rd Qu.:-2.0058   3rd Qu.:-2.70840  
##  Max.   : 4.9498   Max.   : 5.417   Max.   : 0.4163   Max.   :-0.03283  
##                                                                         
##   MPE_dep_log2       MPE_ind_log2        male_sex          HLA_MM     
##  Min.   :-3.60823   Min.   :-3.8997   Min.   :0.0000   Min.   :0.000  
##  1st Qu.:-2.92686   1st Qu.:-3.4501   1st Qu.:0.0000   1st Qu.:4.000  
##  Median :-2.45799   Median :-3.1520   Median :1.0000   Median :5.000  
##  Mean   :-2.40099   Mean   :-3.0307   Mean   :0.6158   Mean   :4.373  
##  3rd Qu.:-1.99712   3rd Qu.:-2.7037   3rd Qu.:1.0000   3rd Qu.:5.000  
##  Max.   : 0.05866   Max.   :-0.5724   Max.   :1.0000   Max.   :6.000  
##                                                        NA's   :35     
##  male_sex_donor        KDPI       perfusion_event       CIT        
##  Min.   :0.0000   Min.   :20.00   Min.   :0.0000   Min.   : 3.267  
##  1st Qu.:0.0000   1st Qu.:37.00   1st Qu.:0.0000   1st Qu.:10.267  
##  Median :1.0000   Median :53.00   Median :0.0000   Median :15.325  
##  Mean   :0.5537   Mean   :53.77   Mean   :0.4038   Mean   :15.920  
##  3rd Qu.:1.0000   3rd Qu.:71.00   3rd Qu.:1.0000   3rd Qu.:20.508  
##  Max.   :1.0000   Max.   :93.00   Max.   :1.0000   Max.   :50.133  
##                                   NA's   :21       NA's   :3       
##    infliximab        rec_age         HLAMMGE3      BKV_viremia_time
##  Min.   :0.0000   Min.   :27.00   Min.   :0.0000   Min.   :  22.0  
##  1st Qu.:0.0000   1st Qu.:45.00   1st Qu.:1.0000   1st Qu.: 196.0  
##  Median :0.0000   Median :54.00   Median :1.0000   Median : 735.0  
##  Mean   :0.4915   Mean   :53.15   Mean   :0.8475   Mean   : 693.9  
##  3rd Qu.:1.0000   3rd Qu.:61.00   3rd Qu.:1.0000   3rd Qu.: 952.0  
##  Max.   :1.0000   Max.   :73.00   Max.   :1.0000   Max.   :1854.0  
##                                                                    
##      race_2        race_donor_2      age_donor      CMV_IgG_rec   
##  Min.   :0.0000   Min.   :0.0000   Min.   : 4.00   Min.   :0.000  
##  1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:31.75   1st Qu.:0.000  
##  Median :0.0000   Median :1.0000   Median :42.50   Median :1.000  
##  Mean   :0.4068   Mean   :0.6158   Mean   :40.33   Mean   :0.661  
##  3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:50.00   3rd Qu.:1.000  
##  Max.   :1.0000   Max.   :1.0000   Max.   :69.00   Max.   :1.000  
##                                    NA's   :1                      
##   de_novo_DSA        donor_type    
##  Min.   :0.00000   Min.   :0.0000  
##  1st Qu.:0.00000   1st Qu.:1.0000  
##  Median :0.00000   Median :1.0000  
##  Mean   :0.06215   Mean   :0.7514  
##  3rd Qu.:0.00000   3rd Qu.:1.0000  
##  Max.   :1.00000   Max.   :1.0000  
## 

## Get mean values 
mmale_sex <- mean(data_model_priorImpute$male_sex, na.rm = TRUE)
mmale_sex_donor <- mean(data_model_priorImpute$male_sex_donor, na.rm = TRUE)
mperfusion_event <- mean(data_model_priorImpute$perfusion_event, na.rm = TRUE)
mrec_age <- mean(data_model_priorImpute$rec_age, na.rm = TRUE)
mKDPI <- mean(data_model_priorImpute$KDPI, na.rm = TRUE)
mCIT <- mean(data_model_priorImpute$CIT, na.rm = TRUE)
mHLA_MM <- mean(data_model_priorImpute$HLA_MM, na.rm = TRUE)
mDGF <- mean(data_model_priorImpute$DGF, na.rm = TRUE)

4.2 Explore data

Open code
skim(data_model_priorImpute)
Data summary
Name data_model_priorImpute
Number of rows 177
Number of columns 26
_______________________
Column type frequency:
numeric 26
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
DGF 0 1.00 0.34 0.47 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▅
infection_any 0 1.00 0.42 0.50 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▆
GFR_MDRD 0 1.00 51.90 20.26 8.44 39.07 49.88 64.98 123.48 ▃▇▆▂▁
BKV_event_2 0 1.00 0.21 0.41 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▂
GPL_BC_log2 0 1.00 0.11 1.42 -3.86 -0.74 -0.10 0.85 4.95 ▁▇▇▃▁
MPL_BC_log2 0 1.00 2.00 1.56 -5.53 1.09 2.04 2.94 5.42 ▁▁▃▇▃
GPE_dep_log2 0 1.00 -2.28 0.65 -3.64 -2.67 -2.39 -2.01 0.42 ▂▇▂▁▁
GPE_ind_log2 0 1.00 -2.92 0.73 -3.87 -3.41 -3.16 -2.71 -0.03 ▇▅▁▁▁
MPE_dep_log2 0 1.00 -2.40 0.67 -3.61 -2.93 -2.46 -2.00 0.06 ▆▇▆▁▁
MPE_ind_log2 0 1.00 -3.03 0.57 -3.90 -3.45 -3.15 -2.70 -0.57 ▇▇▃▁▁
male_sex 0 1.00 0.62 0.49 0.00 0.00 1.00 1.00 1.00 ▅▁▁▁▇
HLA_MM 35 0.80 4.37 1.45 0.00 4.00 5.00 5.00 6.00 ▁▁▂▃▇
male_sex_donor 0 1.00 0.55 0.50 0.00 0.00 1.00 1.00 1.00 ▆▁▁▁▇
KDPI 0 1.00 53.77 20.60 20.00 37.00 53.00 71.00 93.00 ▇▇▆▆▅
perfusion_event 21 0.88 0.40 0.49 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▆
CIT 3 0.98 15.92 7.14 3.27 10.27 15.32 20.51 50.13 ▆▇▃▁▁
infliximab 0 1.00 0.49 0.50 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▇
rec_age 0 1.00 53.15 10.49 27.00 45.00 54.00 61.00 73.00 ▂▅▆▇▅
HLAMMGE3 0 1.00 0.85 0.36 0.00 1.00 1.00 1.00 1.00 ▂▁▁▁▇
BKV_viremia_time 0 1.00 693.92 471.35 22.00 196.00 735.00 952.00 1854.00 ▇▇▅▃▁
race_2 0 1.00 0.41 0.49 0.00 0.00 0.00 1.00 1.00 ▇▁▁▁▆
race_donor_2 0 1.00 0.62 0.49 0.00 0.00 1.00 1.00 1.00 ▅▁▁▁▇
age_donor 1 0.99 40.33 14.23 4.00 31.75 42.50 50.00 69.00 ▂▃▇▇▃
CMV_IgG_rec 0 1.00 0.66 0.47 0.00 0.00 1.00 1.00 1.00 ▅▁▁▁▇
de_novo_DSA 0 1.00 0.06 0.24 0.00 0.00 0.00 0.00 1.00 ▇▁▁▁▁
donor_type 0 1.00 0.75 0.43 0.00 1.00 1.00 1.00 1.00 ▂▁▁▁▇

4.3 Variables correlations

Is the missingness correlated with outcomes?

Open code
df2_corr <- data_model_priorImpute %>% mutate(
  NA_perfusion_event = if_else(is.na(perfusion_event), 1, 0),
  NA_HLA_MM = if_else(is.na(HLA_MM), 1, 0)
)

m1 <- glm(NA_perfusion_event ~ DGF, family = 'binomial', data = df2_corr)
summary(m1)
## 
## Call:
## glm(formula = NA_perfusion_event ~ DGF, family = "binomial", 
##     data = df2_corr)
## 
## Coefficients:
##             Estimate Std. Error z value         Pr(>|z|)    
## (Intercept)  -1.9169     0.2765  -6.932 0.00000000000415 ***
## DGF          -0.2803     0.5115  -0.548            0.584    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 128.93  on 176  degrees of freedom
## Residual deviance: 128.62  on 175  degrees of freedom
## AIC: 132.62
## 
## Number of Fisher Scoring iterations: 4

m2 <- glm(NA_perfusion_event ~ infection_any, family = 'binomial', data = df2_corr)
summary(m2)
## 
## Call:
## glm(formula = NA_perfusion_event ~ infection_any, family = "binomial", 
##     data = df2_corr)
## 
## Coefficients:
##               Estimate Std. Error z value        Pr(>|z|)    
## (Intercept)   -2.01490    0.30731  -6.556 0.0000000000551 ***
## infection_any  0.02247    0.46979   0.048           0.962    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 128.93  on 176  degrees of freedom
## Residual deviance: 128.93  on 175  degrees of freedom
## AIC: 132.93
## 
## Number of Fisher Scoring iterations: 4

m3 <- glm(NA_perfusion_event ~ BKV_event_2, family = 'binomial', data = df2_corr)
summary(m2)
## 
## Call:
## glm(formula = NA_perfusion_event ~ infection_any, family = "binomial", 
##     data = df2_corr)
## 
## Coefficients:
##               Estimate Std. Error z value        Pr(>|z|)    
## (Intercept)   -2.01490    0.30731  -6.556 0.0000000000551 ***
## infection_any  0.02247    0.46979   0.048           0.962    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 128.93  on 176  degrees of freedom
## Residual deviance: 128.93  on 175  degrees of freedom
## AIC: 132.93
## 
## Number of Fisher Scoring iterations: 4

m4 <- glm(NA_perfusion_event ~ GFR_MDRD, family = 'binomial', data = df2_corr)
summary(m4)
## 
## Call:
## glm(formula = NA_perfusion_event ~ GFR_MDRD, family = "binomial", 
##     data = df2_corr)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -2.533940   0.655266  -3.867  0.00011 ***
## GFR_MDRD     0.009888   0.011130   0.888  0.37433    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 128.93  on 176  degrees of freedom
## Residual deviance: 128.16  on 175  degrees of freedom
## AIC: 132.16
## 
## Number of Fisher Scoring iterations: 4

How much are variables inter-correlated?

Open code
corrplot(cor(df2_corr, use = "pairwise.complete.obs", method = 'spearman'),
         method = 'square')
## Warning in cor(df2_corr, use = "pairwise.complete.obs", method = "spearman"):
## the standard deviation is zero
## Warning in cor(df2_corr, use = "pairwise.complete.obs", method = "spearman"):
## the standard deviation is zero

path <- "gitignore/figures/sup_figure_1"

if (!file.exists(path)) {
  pdf(path, width = 12, height = 12) 
  corrplot(cor(df2_corr, use = "pairwise.complete.obs", method = 'spearman'),
         method = 'square')
  dev.off() 
}
Figure 1: Spearman correlations between all variables, including transplant outcomes, natural antibody levels, and various clinical characteristics.

4.4 Multiple imputation

Open code
set.seed(2025)

init <- mice(data_model_priorImpute, maxit = 0)
init$method["perfusion_event"] <- "logreg"

data_imputed <- run(
  expr = mice(
    data_model_priorImpute,
    method = init$method,
    m = 80
  ),
  path = "gitignore/run/data_imputed"
)

## Get the 1st imputed dataset
data_first <- complete(data_imputed, 'all')[1]$`1`

5 Data points of nAB levels

Open code

plotac <- "figure_1"
path <- "gitignore/figures"

 cole <- c(
   "#E89C20", "#803800",
   "#4C60FF", "#001070"
 )


 data_model_priorImpute <- data_model_priorImpute %>%
   mutate(
     group = factor(if_else(infliximab == 1, "infliximab", "control")),
     Group = case_when(
       infliximab == 1 & DGF == 0 ~ "IFX_DGF-",
       infliximab == 1 & DGF == 1 ~ "IFX_DGF+",
       infliximab == 0 & DGF == 0 ~ "ctrl_DGF-",
       infliximab == 0 & DGF == 1 ~ "ctrl_DGF+",
     )
   )

 p1 <- data_model_priorImpute %>%
   ggplot(aes(x = Group, y = GPL_BC_log2, color = Group)) +
   geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
   geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
   scale_color_manual(values = cole) +
   # theme(axis.text.x = element_blank()) +
   labs(
     y = expression(log[2] ~ "(aCL IgG [" * mu * "g/ml])"),
     x = NULL
   ) +
   # scale_x_discrete(
   #   labels = c("", "nevim", "n" ,'n')
   #   ) +
   theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
     legend.position = "none"
   )

 p2 <- data_model_priorImpute %>%
   ggplot(aes(x = Group, y = MPL_BC_log2, color = Group)) +
   geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
   geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
   scale_color_manual(values = cole) +
   # theme(axis.text.x = element_blank()) +
   labs(
     y = expression(log[2] ~ "(aCL IgM [" * mu * "g/ml])"),
     x = NULL
   ) +
   # scale_x_discrete(
   #   labels = c("", "nevim", "n" ,'n')
   #   ) +
   theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
     legend.position = "none"
   )


 data_model_priorImpute <- data_model_priorImpute %>%
   mutate(
     group = factor(if_else(infliximab == 1, "infliximab", "control")),
     Group = case_when(
       infliximab == 1 & infection_any == 0 ~ "IFX_non-infected",
       infliximab == 1 & infection_any == 1 ~ "IFX_infected",
       infliximab == 0 & infection_any == 0 ~ "ctrl_non-infected",
       infliximab == 0 & infection_any == 1 ~ "ctrl_infected",
     )
   )

 p3 <- data_model_priorImpute %>%
   ggplot(aes(x = Group, y = GPE_dep_log2, color = Group)) +
   geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
   geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
   scale_color_manual(values = cole) +
   # theme(axis.text.x = element_blank()) +
   labs(
     y = expression(log[2] ~ "(aPE IgG dep [OD])"),
     x = NULL
   ) +
   # scale_x_discrete(
   #   labels = c("", "nevim", "n" ,'n')
   #   ) +
   theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
     legend.position = "none"
   )

 p4 <- data_model_priorImpute %>%
   ggplot(aes(x = Group, y = GPE_ind_log2, color = Group)) +
   geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
   geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
   scale_color_manual(values = cole) +
   # theme(axis.text.x = element_blank()) +
   labs(
     y = expression(log[2] ~ "(aPE IgG ind [OD])"),
     x = NULL
   ) +
   # scale_x_discrete(
   #   labels = c("", "nevim", "n" ,'n')
   #   ) +
   theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
     legend.position = "none"
   )

 p5 <- data_model_priorImpute %>%
   ggplot(aes(x = Group, y = MPE_dep_log2, color = Group)) +
   geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
   geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
   scale_color_manual(values = cole) +
   # theme(axis.text.x = element_blank()) +
   labs(
     y = expression(log[2] ~ "(aPE IgM dep [OD])"),
     x = NULL
   ) +
   # scale_x_discrete(
   #   labels = c("", "nevim", "n" ,'n')
   #   ) +
   theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
     legend.position = "none"
   )

 p6 <- data_model_priorImpute %>%
   ggplot(aes(x = Group, y = MPE_ind_log2, color = Group)) +
   geom_boxplot(outlier.shape = NA, fill = NA, width = 0.8) +
   geom_beeswarm(alpha = 0.5, cex = 2.3, size = 1.4) +
   scale_color_manual(values = cole) +
   # theme(axis.text.x = element_blank()) +
   labs(
     y = expression(log[2] ~ "(aPE IgM ind [OD])"),
     x = NULL
   ) +
   # scale_x_discrete(
   #   labels = c("", "nevim", "n" ,'n')
   #   ) +
   theme(
     axis.text.x = element_text(angle = 45, hjust = 1),
     legend.position = "none"
   )

 if (!file.exists(paste0(path, "/", plotac, ".pdf"))) {
   assign(
     plotac,
     cowplot::plot_grid(p1, p2, p3, p4, p5, p6,
       labels = c("A", "B", "C", "D", "E", "F"),
       ncol = 2, nrow = , rel_heights = c(1, 1.1, 1.1)
     )
   )

   ggsave(
     path = paste0(path),
     filename = plotac,
     device = "pdf",
     width = 6,
     height = 10
   )
 }

 get(plotac)
Figure 2: Distribution of natural antibody levels across groups defined by treatment (infliximab [IFX] vs. control [ctrl]) and key post-transplant outcomes: occurrence of peritransplant delayed graft function [DGF+ vs. DGF−; A to B] or post-transplant infection [“infected” vs. “non-infected”; C to F]. (A) Levels of anti-cardiolipin IgG. (B) Levels of anti-cardiolipin IgM. (C) Levels of co-factor-dependent anti-phosphatidylethanolamine IgG. (D) Levels of co-factor-independent anti-phosphatidylethanolamine IgG. (E) Levels of co-factor-dependent anti-phosphatidylethanolamine IgM. (F) Levels of co-factor-independent anti-phosphatidylethanolamine IgM.

6 Unadjsuted ORs for DGF

Definition of function

Open code
univar_mod <- function(dat, 
                       outcome, 
                       predictors,
                       family = "logistic", 
                       level = 0.95,
                       rounding = 2
                       ) {
  
  N <- vector("double", length(predictors))
  OR <- vector("double", length(predictors))
  CI_L <- vector("double", length(predictors))
  CI_U <- vector("double", length(predictors))
  predictor <- vector("double", length(predictors))

  for (i in 1:length(predictors)) {
  
    data <- dat %>% dplyr::select(outcome, 
                                  all_of(unlist(strsplit(predictors[i], "\\*"))))
    data <- na.omit(data)

    N[i] <- nrow(data)

    formula <- paste0(outcome, " ~ ", predictors[i])

    if (family == "logistic") {
       suppressMessages(suppressWarnings({
      model <- glm(formula, data = data, family = "binomial"(link = "logit"))
      OR[i] <- exp(coef(model)[length(coef(model))])
      CI_L[i] <- exp(confint(model, level = level)[length(coef(model)), ])[1]
      CI_U[i] <- exp(confint(model, level = level)[length(coef(model)), ])[2]

      predictor[i] <- names(coef(model)[length(coef(model))])

      result <- data.frame(
        predictor, 
        OR = paste0(round(OR, rounding), ' [',round(CI_L, rounding), ', ',
                    round(CI_U, rounding),']'),
        N
      )
       }))
    } else if (family == "gaussian") {
       suppressMessages(suppressWarnings({
      model <- lm(formula, data = data)
      OR[i] <- coef(model)[length(coef(model))]
      CI_L[i] <- confint(model, level = level)[length(coef(model)), ][1]
      CI_U[i] <- confint(model, level = level)[length(coef(model)), ][2]

      predictor[i] <- names(coef(model)[length(coef(model))])

      result <- data.frame(
        predictor,
        effect = paste0(round(OR, rounding), ' [',round(CI_L, rounding), ', ',
                    round(CI_U, rounding),']'),
        N
      )
       }))
    } else {
      stop("incorrect family specification pyco", call. = FALSE)
    }
  }
  
  return(result)
}

preds <- c(
  "infliximab",
  "GPL_BC_log2", "MPL_BC_log2",
  "GPE_dep_log2", "GPE_ind_log2",
  "MPE_dep_log2", "MPE_ind_log2",
  "male_sex", "HLA_MM", "male_sex_donor", "KDPI",
  "perfusion_event", "CIT", "rec_age", "DGF",
  "infliximab*GPL_BC_log2", "infliximab*MPL_BC_log2",
  "infliximab*GPE_dep_log2", "infliximab*GPE_ind_log2",
  "infliximab*MPE_dep_log2", "infliximab*MPE_ind_log2"
)

preds_DGF <- c(
  "infliximab",
  "GPL_BC_log2", "MPL_BC_log2",
  "GPE_dep_log2", "GPE_ind_log2",
  "MPE_dep_log2", "MPE_ind_log2",
  "male_sex", "HLA_MM", "male_sex_donor", "KDPI",
  "perfusion_event", "CIT", "rec_age",
  "infliximab*GPL_BC_log2", "infliximab*MPL_BC_log2",
  "infliximab*GPE_dep_log2", "infliximab*GPE_ind_log2",
  "infliximab*MPE_dep_log2", "infliximab*MPE_ind_log2"
)

6.1 DGF

Open code
kableExtra::kable(
  univar_mod(dat = data_model_priorImpute,
           outcome = 'DGF',
           predictors = preds_DGF,
           family = 'logistic',
           rounding = 2
           ) %>% rename(
             `(R)OR` = `OR`
           )
  )
## Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
## ℹ Please use `all_of()` or `any_of()` instead.
##   # Was:
##   data %>% select(outcome)
## 
##   # Now:
##   data %>% select(all_of(outcome))
## 
## See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
Table 4: Results from univariable logistic regression models assessing the effects of variables on delayed graft function (DGF) in patients with complete data for given predictor. The odds ratio (OR) represents the estimated change in DGF odds per one-unit increase in the predictor. For interaction terms, the ratio of odds ratios (ROR) quantifies the ratio of the infliximab effect (OR) on DGF at a given natural antibody (nAb) level to its effect when the nAb level is halved. A 95% confidence interval including 1 suggests no significant modification of the infliximab effect by nAb levels. (R)OR: odds ratio (for main effects) or ratio of odds ratios (for interactions) [95% confidence interval]. N: number of observations.
predictor (R)OR N
infliximab 0.86 [0.46, 1.6] 177
GPL_BC_log2 1.08 [0.86, 1.34] 177
MPL_BC_log2 1.2 [0.98, 1.5] 177
GPE_dep_log2 1 [0.61, 1.61] 177
GPE_ind_log2 1.02 [0.66, 1.55] 177
MPE_dep_log2 1.08 [0.67, 1.73] 177
MPE_ind_log2 0.96 [0.54, 1.64] 177
male_sex 2.2 [1.13, 4.43] 177
HLA_MM 1.25 [0.97, 1.65] 142
male_sex_donor 1.08 [0.58, 2.04] 177
KDPI 1.01 [0.99, 1.02] 177
perfusion_event 0.91 [0.46, 1.78] 156
CIT 1.07 [1.02, 1.12] 174
rec_age 0.99 [0.96, 1.02] 177
infliximab:GPL_BC_log2 1.84 [1.15, 3.02] 177
infliximab:MPL_BC_log2 1.52 [0.97, 2.43] 177
infliximab:GPE_dep_log2 1 [0.38, 2.62] 177
infliximab:GPE_ind_log2 1.04 [0.43, 2.45] 177
infliximab:MPE_dep_log2 2.32 [0.89, 6.21] 177
infliximab:MPE_ind_log2 1.59 [0.52, 5.04] 177

6.2 GFR

Open code
kableExtra::kable(
  univar_mod(dat = data_model_priorImpute,
           outcome = 'GFR_MDRD',
           predictors = preds,
           family = 'gaussian',
           rounding = 1
           ) 
  )
Table 5: Results from univariable linear models assessing the effects of variables on estimated glomerula filtration rate (eGFR) in patients with complete data for given predictor. Effect [95% confidennce interval] is shown and represents the estimated change in eGFR per one-unit increase in the predictor. For interaction terms, the effect quantifies the difference in the infliximab effect on eGFR at a given natural antibody (nAb) level vs its effect when the nAb level is halved. A 95% confidence interval including 0 suggests no significant modification of the infliximab effect by nAb levels. N: number of observations.
predictor effect N
infliximab -3.9 [-9.9, 2.1] 177
GPL_BC_log2 1.1 [-1, 3.2] 177
MPL_BC_log2 -0.3 [-2.3, 1.6] 177
GPE_dep_log2 1.5 [-3.2, 6.1] 177
GPE_ind_log2 -2.8 [-6.9, 1.3] 177
MPE_dep_log2 2.6 [-2, 7.1] 177
MPE_ind_log2 0.5 [-4.8, 5.8] 177
male_sex -3.4 [-9.6, 2.7] 177
HLA_MM -3.2 [-5.5, -1] 142
male_sex_donor 4.8 [-1.3, 10.8] 177
KDPI -0.2 [-0.3, -0.1] 177
perfusion_event -6.8 [-13.1, -0.5] 156
CIT 0.1 [-0.3, 0.6] 174
rec_age -0.1 [-0.3, 0.2] 177
DGF -15.9 [-21.8, -10] 177
infliximab:GPL_BC_log2 -5.6 [-9.9, -1.3] 177
infliximab:MPL_BC_log2 -4.7 [-8.6, -0.8] 177
infliximab:GPE_dep_log2 0.9 [-8.4, 10.1] 177
infliximab:GPE_ind_log2 0.8 [-7.5, 9.1] 177
infliximab:MPE_dep_log2 -3.4 [-12.6, 5.8] 177
infliximab:MPE_ind_log2 2.3 [-8.3, 13] 177

6.3 Infection

Open code
kableExtra::kable(
  univar_mod(dat = data_model_priorImpute,
           outcome = 'infection_any',
           predictors = preds,
           family = 'logistic'
           )%>% rename(
             `(R)OR` = `OR`
           )
)
Table 6: Results from univariable logistic regression models assessing the effects of variables on infection risk in patients with complete data for given predictor. The odds ratio (OR) represents the estimated change in odds of infection per one-unit increase in the predictor. For interaction terms, the ratio of odds ratios (ROR) quantifies the ratio of the infliximab effect (OR) on infection at a given natural antibody (nAb) level to its effect when the nAb level is halved. A 95% confidence interval including 1 suggests no significant modification of the infliximab effect by nAb levels. (R)OR: odds ratio (for main effects) or ratio of odds ratios (for interactions) [95% confidence interval]. N: number of observations.
predictor (R)OR N
infliximab 1.11 [0.61, 2.02] 177
GPL_BC_log2 0.91 [0.73, 1.12] 177
MPL_BC_log2 0.94 [0.77, 1.14] 177
GPE_dep_log2 0.68 [0.42, 1.09] 177
GPE_ind_log2 0.66 [0.41, 1.02] 177
MPE_dep_log2 0.84 [0.53, 1.32] 177
MPE_ind_log2 1.09 [0.64, 1.84] 177
male_sex 0.98 [0.53, 1.82] 177
HLA_MM 0.88 [0.69, 1.11] 142
male_sex_donor 0.87 [0.48, 1.58] 177
KDPI 1.02 [1, 1.04] 177
perfusion_event 0.75 [0.39, 1.43] 156
CIT 0.93 [0.89, 0.98] 174
rec_age 1 [0.97, 1.02] 177
DGF 1.18 [0.63, 2.2] 177
infliximab:GPL_BC_log2 1.23 [0.79, 1.92] 177
infliximab:MPL_BC_log2 1.22 [0.82, 1.83] 177
infliximab:GPE_dep_log2 0.35 [0.12, 0.94] 177
infliximab:GPE_ind_log2 0.31 [0.1, 0.83] 177
infliximab:MPE_dep_log2 0.49 [0.19, 1.23] 177
infliximab:MPE_ind_log2 1 [0.35, 2.9] 177

6.4 BKV

Open code
kableExtra::kable(
  univar_mod(dat = data_model_priorImpute,
           outcome = 'BKV_event_2',
           predictors = preds,
           family = 'logistic',
           rounding = 2
           ) %>% rename(
             `(R)OR` = `OR`)
)
Table 7: Results from univariable logistic regression models assessing the effects of variables on BKV infection risk in patients with complete data for given predictor. The odds ratio (OR) represents the estimated change in odds of BKV infection per one-unit increase in the predictor. For interaction terms, the ratio of odds ratios (ROR) quantifies the ratio of the infliximab effect (OR) on BKV infection at a given natural antibody (nAb) level to its effect when the nAb level is halved. A 95% confidence interval including 1 suggests no significant modification of the infliximab effect by nAb levels. (R)OR: odds ratio (for main effects) or ratio of odds ratios (for interactions) [95% confidence interval]. N: number of observations.
predictor (R)OR N
infliximab 2.39 [1.15, 5.18] 177
GPL_BC_log2 0.83 [0.63, 1.07] 177
MPL_BC_log2 1.12 [0.89, 1.44] 177
GPE_dep_log2 0.72 [0.39, 1.27] 177
GPE_ind_log2 1.01 [0.59, 1.6] 177
MPE_dep_log2 1.13 [0.66, 1.93] 177
MPE_ind_log2 1.22 [0.65, 2.2] 177
male_sex 1.71 [0.8, 3.84] 177
HLA_MM 1.12 [0.84, 1.55] 142
male_sex_donor 0.38 [0.18, 0.79] 177
KDPI 0.99 [0.98, 1.01] 177
perfusion_event 1.28 [0.57, 2.82] 156
CIT 0.95 [0.89, 1] 174
rec_age 1.03 [0.99, 1.06] 177
DGF 1.36 [0.64, 2.84] 177
infliximab:GPL_BC_log2 1.34 [0.77, 2.41] 177
infliximab:MPL_BC_log2 1.1 [0.65, 1.86] 177
infliximab:GPE_dep_log2 1.57 [0.44, 6.14] 177
infliximab:GPE_ind_log2 0.49 [0.17, 1.33] 177
infliximab:MPE_dep_log2 1 [0.31, 3.22] 177
infliximab:MPE_ind_log2 1.37 [0.4, 5.26] 177

7 DGF models

7.1 DGF by GPL_BC

7.1.1 Priors

Open code
# function to get prior
create_prior <- function(var, sigma, class = "b", coef = NULL) {
  set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = coef)
}

scaling_unit <- 1

7.1.1.1 Main effects model

Open code
priors_main <- c(
  create_prior("GPL_BC_log2",
    2 / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
    coef = "GPL_BC_log2"
  ),
   create_prior("IHLA_MMM5",
    2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
    class = "Intercept"
  )
)

7.1.1.2 Non-linear penalized interaction model

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
               coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
               coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
               coef = "IKDPIM50"),
  create_prior("ICITM15",
               2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
               coef = "ICITM15"),
  create_prior("male_sex",
               4,
               coef = "male_sex"),
  create_prior("perfusion_event",
               4,
               coef = "perfusion_event"),
  create_prior("male_sex_donor",
               4,
               coef = "male_sex_donor"),

  create_prior("infliximab",
               4,
               coef = "infliximab"),

 set_prior("student_t(3, 0, 0.6)", class = "sds", 
           coef = 's(GPL_BC_log2, bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 0.3)", class = "sds",  
           coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
            class = "Intercept")
)

7.1.2 Models

7.1.2.1 Main effects models

Open code
model_dgf_GPL_BC_main <- run(
  expr = brm_multiple(
    DGF ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      GPL_BC_log2,
    family = bernoulli(),
    data = data_imputed,
    prior = priors_main,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_GPL_BC_main",
  reuse = TRUE
)

summary(model_dgf_GPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          -0.75      0.48    -1.70     0.18 1.01    18087    26121
## male_sex            0.81      0.38     0.07     1.58 1.01    35270    27169
## Irec_ageM50        -0.02      0.02    -0.05     0.01 1.01    35275    27008
## male_sex_donor      0.10      0.37    -0.62     0.83 1.01    35510    27598
## IKDPIM50            0.01      0.01    -0.01     0.02 1.01    36654    26896
## ICITM15             0.08      0.03     0.02     0.13 1.02    11475    27045
## IHLA_MMM5           0.26      0.13     0.01     0.53 1.06     3602    18106
## perfusion_event    -0.65      0.40    -1.45     0.13 1.06     3524    13012
## infliximab         -0.33      0.35    -1.04     0.37 1.01    37331    27918
## GPL_BC_log2         0.05      0.13    -0.20     0.29 1.01    37266    27873
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_GPL_BC_main)
##                           prior     class            coef group resp dpar nlpar
##                          (flat)         b                                      
##     normal(0, 1.41170525720746)         b     GPL_BC_log2                      
##    normal(0, 0.280307006032291)         b         ICITM15                      
##     normal(0, 1.38219051128263)         b       IHLA_MMM5                      
##   normal(0, 0.0970980394231448)         b        IKDPIM50                      
##                    normal(0, 4)         b      infliximab                      
##    normal(0, 0.190589762164436)         b     Irec_ageM50                      
##                    normal(0, 4)         b        male_sex                      
##                    normal(0, 4)         b  male_sex_donor                      
##                    normal(0, 4)         b perfusion_event                      
##  normal(-0.667829372575656, 10) Intercept                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user

tr <- round(exp(fixef(model_dgf_GPL_BC_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)
Table 8: Results from multivariable Bayesian logistic regression models examining the main effects of predictors, including infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on delayed graft function (DGF), without interaction terms. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
OR Q2.5 Q97.5
male_sex 2.25 1.07 4.87
Irec_ageM50 0.98 0.95 1.01
male_sex_donor 1.11 0.54 2.28
IKDPIM50 1.01 0.99 1.02
ICITM15 1.08 1.02 1.14
IHLA_MMM5 1.30 1.01 1.70
perfusion_event 0.52 0.23 1.14
infliximab 0.72 0.35 1.45
GPL_BC_log2 1.05 0.81 1.34

7.1.2.2 Non-linear interaction model

Open code
model_dgf_GPL_BC_interaction_NL <- run(
  expr = brm_multiple(
    DGF ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(GPL_BC_log2, bs = 'ps', k = 5) +
    s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_GPL_BC_interaction_NL",
  reuse = TRUE
)

summary(model_dgf_GPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Smoothing Spline Hyperparameters:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1)               0.83      0.61     0.05     2.95 1.02
## sds(sGPL_BC_log2infliximab_1)     0.23      0.21     0.01     1.16 1.01
##                               Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1)              14045    12820
## sds(sGPL_BC_log2infliximab_1)    27968    14350
## 
## Regression Coefficients:
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                    -0.88      0.49    -1.87     0.07 1.02    14612
## male_sex                      0.97      0.40     0.20     1.80 1.01    35062
## Irec_ageM50                  -0.02      0.02    -0.06     0.01 1.01    34006
## male_sex_donor                0.29      0.39    -0.47     1.06 1.01    34337
## IKDPIM50                      0.01      0.01    -0.01     0.03 1.01    34534
## ICITM15                       0.08      0.03     0.03     0.14 1.02     8750
## IHLA_MMM5                     0.31      0.14     0.05     0.60 1.06     3297
## perfusion_event              -0.75      0.43    -1.61     0.07 1.08     2768
## infliximab                    0.02      3.90    -7.66     7.65 1.02    12394
## sGPL_BC_log2_1               -1.27      1.52    -4.37     2.91 1.01    19570
## sGPL_BC_log2:infliximab_1     2.30      2.41    -2.36     7.02 1.02    13785
## sGPL_BC_log2:infliximab_2    -2.66      1.62    -5.80     0.53 1.01    14601
##                           Tail_ESS
## Intercept                    29212
## male_sex                     26720
## Irec_ageM50                  27092
## male_sex_donor               26886
## IKDPIM50                     27506
## ICITM15                      25453
## IHLA_MMM5                    11332
## perfusion_event               9621
## infliximab                   18177
## sGPL_BC_log2_1               15385
## sGPL_BC_log2:infliximab_1    20359
## sGPL_BC_log2:infliximab_2    22043
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_GPL_BC_interaction_NL)
##                           prior     class
##                          (flat)         b
##    normal(0, 0.280307006032291)         b
##     normal(0, 1.38219051128263)         b
##   normal(0, 0.0970980394231448)         b
##                    normal(0, 4)         b
##    normal(0, 0.190589762164436)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                          (flat)         b
##                          (flat)         b
##                          (flat)         b
##  normal(-0.667829372575656, 10) Intercept
##            student_t(3, 0, 2.5)       sds
##            student_t(3, 0, 0.6)       sds
##            student_t(3, 0, 0.3)       sds
##                                               coef group resp dpar nlpar lb ub
##                                                                               
##                                            ICITM15                            
##                                          IHLA_MMM5                            
##                                           IKDPIM50                            
##                                         infliximab                            
##                                        Irec_ageM50                            
##                                           male_sex                            
##                                     male_sex_donor                            
##                                    perfusion_event                            
##                                     sGPL_BC_log2_1                            
##                          sGPL_BC_log2:infliximab_1                            
##                          sGPL_BC_log2:infliximab_2                            
##                                                                               
##                                                                           0   
##                   s(GPL_BC_log2, bs = "ps", k = 5)                        0   
##  s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)                        0   
##        source
##       default
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##  (vectorized)
##  (vectorized)
##  (vectorized)
##          user
##       default
##          user
##          user

tr2 <- round(exp(fixef(model_dgf_GPL_BC_interaction_NL, 
                       robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)

antibody_seq <- quantile(data_model_priorImpute$GPL_BC_log2, 
                         probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
  `male_sex` = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_dgf_GPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get odds ratio for infliximab effect across antibody values
prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()
names(prediction) <- c('p05', 'p95')

infliximab_GPL_BC_log2_int <- quantile(
  exp((log(prediction$p95) - log(prediction$p05))/scaling_unit), 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)
Table 9: Results from multivariable Bayesian logistic regression models incorporating a non-linear interaction between anti-cardiolipin IgG (GPL_BC_log2) and infliximab treatment on delayed graft function (DGF), while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
(R)OR Q2.5 Q97.5
male_sex 2.64 1.23 6.02
Irec_ageM50 0.98 0.94 1.01
male_sex_donor 1.34 0.62 2.88
IKDPIM50 1.01 0.99 1.03
ICITM15 1.09 1.03 1.15
IHLA_MMM5 1.36 1.05 1.83
perfusion_event 0.47 0.20 1.07
infliximab:GPL_BC_log2 46.56 4.36 610.02

7.1.3 Visualisation

Extract posterior draws

Open code
antibody_perc <- quantile(data_model_priorImpute$GPL_BC_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_dgf_GPL_BC_interaction_NL,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')), 
  GPL_BC_log2 = data_prediction$GPL_BC_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control"))) %>% 
  ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 1),
                     breaks = c(seq(0, 1, by = 0.2))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"), y = "DGF risk") +
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") +
  
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 0),
    aes(x = GPL_BC_log2),
    sides = "b",
    color = "black",
    linewidth = 0.12,
    inherit.aes = FALSE
  ) +
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 1),
    aes(x = GPL_BC_log2),
     sides = "t",
    color = "black",
    linewidth = 0.12,
    inherit.aes = FALSE
  ) + 
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##        0%      100% 
## -3.861561  4.949819

tr <-  posterior_epred(
    model_dgf_GPL_BC_interaction_NL,
    newdata = data_prediction)

tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)])) /
  (antibody_seq[2] - antibody_seq[1])
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_GPL_BC_log2 = tr_ctrl,
  b_GPL_BC_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = exp(b_GPL_BC_log2), 
         infliximab = exp(b_GPL_BC_log2_infliximab)) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(1)

CIS
##       control infliximab
## 2.5%      0.5        1.2
## 97.5%     1.1        3.2
## 50%       0.8        1.9
## 0.1%      0.4        0.9
## 99.9%     1.4        4.8

xpos <- 10

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aCL IgG on DGF risk (OR))", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(1/20, 20)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(1/16, 1/4, 1, 4 ,16),
                     labels = c("1/16", "1/4", "1", "4", "16")) +
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
##         5%        25%        50%        75%        95% 
## -1.8016683 -0.7449060 -0.1046076  0.8504991  2.5318211
antibody_seq**2
##         5%        25%        50%        75%        95% 
## 3.24600871 0.55488501 0.01094276 0.72334876 6.41011830

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_dgf_GPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()


names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##        p05  p25  p50  p75   p95
## 2.5%  0.03 0.13 0.27 0.60  1.38
## 97.5% 0.49 0.80 1.25 3.22 30.32
## 50%   0.13 0.34 0.59 1.37  6.24
## 0.1%  0.01 0.07 0.17 0.37  0.60
## 99.9% 1.02 1.28 1.93 5.41 82.13

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'GPL_BC_percentile') %>% 
  
  ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on DGF risk (odds ratio)", 
         y = 'Percentile of aCL IgG value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(1/300, 1150)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(xseq),
                     labels = c("1/64", "1/8", "1", "8", "64", '512')) +
  
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Odds ratio: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Odds ratio: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Odds ratio: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

7.1.3.1 Figure merged

Open code
plotac <- 'figure_2'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 3: Anti-cardiolipin IgG modulates infliximab effect on delayed graft function. (A) Predicted DGF risk by anti-cardiolipin IgG for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regiond) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of cardiolipin levels. (B) Posterior distribution for the average effect (odds ratio) of doubling anti-cardiolipin IgG on DGF risk. (C) Posterior distribution of the infliximab effect (odds ratio) on DGF risk across anti-cardiolipin IgG percentiles. Results are from a multivariable Bayesian logistic model with B-splines.

7.2 DGF by MPL_BC

7.2.1 Priors

7.2.1.1 Main effects model

Open code
priors_main <- c(
  create_prior("IMPL_BC_log2M2",
    2 / sd(data_model_priorImpute$MPL_BC_log2, na.rm = TRUE),
    coef = "IMPL_BC_log2M2"
  ),
   create_prior("IHLA_MMM5",
    2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
    class = "Intercept"
  )
)

7.2.1.2 Non-linear penalized interaction model

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
               coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
               coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
               coef = "IKDPIM50"),
  create_prior("ICITM15",
               2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
               coef = "ICITM15"),
  create_prior("male_sex",
               4,
               coef = "male_sex"),
  create_prior("perfusion_event",
               4,
               coef = "perfusion_event"),
  create_prior("male_sex_donor",
               4,
               coef = "male_sex_donor"),

  create_prior("infliximab",
               4,
               coef = "infliximab"),
  
 set_prior("student_t(3, 0, 0.6)", class = "sds", 
           coef = 's(I(MPL_BC_log2 - 2), bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 0.3)", class = "sds",  
           coef = 's(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
            class = "Intercept")
)

7.2.2 Models

7.2.2.1 Main effects models

Open code
set.seed(2025)
model_dgf_MPL_BC_main <- run(
  expr = brm_multiple(
    DGF ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      I(MPL_BC_log2 - 2),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_main,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_MPL_BC_main",
  reuse = TRUE
)

summary(model_dgf_MPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(MPL_BC_log2 - 2) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          -0.88      0.48    -1.85     0.05 1.02    14414    25568
## male_sex            0.89      0.39     0.14     1.69 1.01    35387    28013
## Irec_ageM50        -0.02      0.02    -0.06     0.01 1.01    37218    27652
## male_sex_donor      0.14      0.37    -0.59     0.87 1.01    36459    27773
## IKDPIM50            0.01      0.01    -0.01     0.02 1.01    36554    27839
## ICITM15             0.07      0.03     0.02     0.13 1.02    11114    26679
## IHLA_MMM5           0.25      0.13    -0.00     0.52 1.06     3433    12047
## perfusion_event    -0.61      0.41    -1.45     0.19 1.07     3180    11578
## infliximab         -0.24      0.36    -0.97     0.48 1.01    35927    27005
## IMPL_BC_log2M2      0.20      0.12    -0.04     0.44 1.01    35829    26440
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_MPL_BC_main)
##                           prior     class            coef group resp dpar nlpar
##                          (flat)         b                                      
##    normal(0, 0.280307006032291)         b         ICITM15                      
##     normal(0, 1.38219051128263)         b       IHLA_MMM5                      
##   normal(0, 0.0970980394231448)         b        IKDPIM50                      
##     normal(0, 1.27934317633706)         b  IMPL_BC_log2M2                      
##                    normal(0, 4)         b      infliximab                      
##    normal(0, 0.190589762164436)         b     Irec_ageM50                      
##                    normal(0, 4)         b        male_sex                      
##                    normal(0, 4)         b  male_sex_donor                      
##                    normal(0, 4)         b perfusion_event                      
##  normal(-0.667829372575656, 10) Intercept                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user

tr <- round(exp(fixef(model_dgf_MPL_BC_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)
Table 10: Results from multivariable Bayesian logistic regression models examining the main effects of predictors, including infliximab treatment and log2-transformed anti-cardiolipin IgM (MPL_BC_log2), on delayed graft function (DGF), without interaction terms. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
OR Q2.5 Q97.5
male_sex 2.44 1.15 5.40
Irec_ageM50 0.98 0.95 1.01
male_sex_donor 1.15 0.56 2.40
IKDPIM50 1.01 0.99 1.02
ICITM15 1.08 1.02 1.14
IHLA_MMM5 1.28 1.00 1.69
perfusion_event 0.55 0.23 1.21
infliximab 0.79 0.38 1.61
IMPL_BC_log2M2 1.22 0.96 1.56

7.2.2.2 Non-linear interaction model

Open code
set.seed(2025)
model_dgf_MPL_BC_interaction_NL <- run(
  expr = brm_multiple(
    DGF ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +   
    s(I(MPL_BC_log2-2), bs = 'ps', k = 5) +
    s(I(MPL_BC_log2-2), by = infliximab, bs = 'ps', k = 5),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_MPL_BC_interaction_NL",
  reuse = TRUE
)

summary(model_dgf_MPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(MPL_BC_log2 - 2), bs = "ps", k = 5) + s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Smoothing Spline Hyperparameters:
##                                  Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIMPL_BC_log2M2_1)               0.42      0.38     0.02     1.87 1.01
## sds(sIMPL_BC_log2M2infliximab_1)     0.22      0.20     0.01     1.07 1.00
##                                  Bulk_ESS Tail_ESS
## sds(sIMPL_BC_log2M2_1)              22288    15370
## sds(sIMPL_BC_log2M2infliximab_1)    31518    16326
## 
## Regression Coefficients:
##                              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                       -0.88      0.49    -1.86     0.05 1.02    18653
## male_sex                         0.90      0.39     0.14     1.70 1.01    36356
## Irec_ageM50                     -0.03      0.02    -0.06     0.01 1.01    34817
## male_sex_donor                   0.23      0.38    -0.51     1.00 1.01    36879
## IKDPIM50                         0.01      0.01    -0.01     0.02 1.01    35932
## ICITM15                          0.07      0.03     0.02     0.13 1.02    15639
## IHLA_MMM5                        0.25      0.13     0.00     0.53 1.06     3408
## perfusion_event                 -0.58      0.42    -1.42     0.23 1.08     2747
## infliximab                      -0.08      3.95    -7.77     7.71 1.02    12781
## sIMPL_BC_log2M2_1                0.36      1.27    -2.13     3.27 1.01    23892
## sIMPL_BC_log2M2:infliximab_1     1.13      2.95    -4.69     6.87 1.02    13362
## sIMPL_BC_log2M2:infliximab_2    -1.55      1.23    -4.00     0.82 1.01    16755
##                              Tail_ESS
## Intercept                       28581
## male_sex                        25744
## Irec_ageM50                     26590
## male_sex_donor                  27123
## IKDPIM50                        27389
## ICITM15                         24626
## IHLA_MMM5                       11220
## perfusion_event                  9277
## infliximab                      17925
## sIMPL_BC_log2M2_1               20627
## sIMPL_BC_log2M2:infliximab_1    18672
## sIMPL_BC_log2M2:infliximab_2    23546
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_MPL_BC_interaction_NL)
##                           prior     class
##                          (flat)         b
##    normal(0, 0.280307006032291)         b
##     normal(0, 1.38219051128263)         b
##   normal(0, 0.0970980394231448)         b
##                    normal(0, 4)         b
##    normal(0, 0.190589762164436)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                          (flat)         b
##                          (flat)         b
##                          (flat)         b
##  normal(-0.667829372575656, 10) Intercept
##            student_t(3, 0, 2.5)       sds
##            student_t(3, 0, 0.6)       sds
##            student_t(3, 0, 0.3)       sds
##                                                      coef group resp dpar nlpar
##                                                                                
##                                                   ICITM15                      
##                                                 IHLA_MMM5                      
##                                                  IKDPIM50                      
##                                                infliximab                      
##                                               Irec_ageM50                      
##                                                  male_sex                      
##                                            male_sex_donor                      
##                                           perfusion_event                      
##                                         sIMPL_BC_log2M2_1                      
##                              sIMPL_BC_log2M2:infliximab_1                      
##                              sIMPL_BC_log2M2:infliximab_2                      
##                                                                                
##                                                                                
##                   s(I(MPL_BC_log2 - 2), bs = "ps", k = 5)                      
##  s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)                      
##  lb ub       source
##             default
##                user
##                user
##                user
##                user
##                user
##                user
##                user
##                user
##        (vectorized)
##        (vectorized)
##        (vectorized)
##                user
##   0         default
##   0            user
##   0            user


tr2 <- round(exp(fixef(model_dgf_MPL_BC_interaction_NL, robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)

antibody_seq <- quantile(data_model_priorImpute$MPL_BC_log2, probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `MPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_dgf_MPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get odds ratio for infliximab effect across antibody values
prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()
names(prediction) <- c('p05', 'p95')

infliximab_MPL_BC_log2_int <- quantile(exp((log(prediction$p95) - log(prediction$p05))/scaling_unit), 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_MPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:MPL_BC_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)
Table 11: Results from multivariable Bayesian logistic regression models incorporating a non-linear interaction between anti-cardiolipin IgM (MPL_BC_log2) and infliximab treatment on delayed graft function (DGF), while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
(R)OR Q2.5 Q97.5
male_sex 2.47 1.14 5.49
Irec_ageM50 0.98 0.94 1.01
male_sex_donor 1.26 0.60 2.71
IKDPIM50 1.01 0.99 1.02
ICITM15 1.08 1.02 1.14
IHLA_MMM5 1.29 1.00 1.70
perfusion_event 0.56 0.24 1.26
infliximab:MPL_BC_log2 12.18 1.07 165.59

7.2.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_model_priorImpute$MPL_BC_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `MPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_dgf_MPL_BC_interaction_NL,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')), 
  MPL_BC_log2 = data_prediction$MPL_BC_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control"))) %>% 
  ggplot(aes(x = MPL_BC_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 1),
                     breaks = c(seq(0, 1, by = 0.2))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  labs(x = expression(log[2]~"(aCL IgM ["*mu*"g/ml])"), y = "DGF risk") +
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") +
  
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 0),
    aes(x = MPL_BC_log2),
    sides = "b",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  ) +
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 1),
    aes(x = MPL_BC_log2),
     sides = "t",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  )  + 
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##        0%      100% 
## -5.532591  5.416829

tr <-  posterior_epred(
    model_dgf_MPL_BC_interaction_NL,
    newdata = data_prediction)

tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)])) /
  (antibody_seq[2] - antibody_seq[1])

tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_MPL_BC_log2 = tr_ctrl,
  b_MPL_BC_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = exp(b_MPL_BC_log2), 
         infliximab = exp(b_MPL_BC_log2_infliximab)) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##       control infliximab
## 2.5%     0.63       1.04
## 97.5%    1.36       2.44
## 50%      0.94       1.54
## 0.1%     0.47       0.81
## 99.9%    1.75       3.30

xpos <- 10

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aCL IgM on DGF risk (OR))", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(1/20, 20)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(1/16, 1/4, 1, 4 ,16),
                     labels = c("1/16", "1/4", "1", "4", "16")) +
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
##         5%        25%        50%        75%        95% 
## -0.3963058  1.0933124  2.0432905  2.9421729  4.5810923

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `MPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_dgf_MPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()

names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##        p05  p25  p50  p75   p95
## 2.5%  0.05 0.19 0.37 0.52  0.66
## 97.5% 0.94 1.15 1.61 2.85 12.59
## 50%   0.23 0.48 0.77 1.22  2.79
## 0.1%  0.02 0.11 0.24 0.32  0.28
## 99.9% 2.07 1.85 2.43 4.75 31.56

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'MPL_BC_percentile') %>% 
  
  ggplot(aes(y = MPL_BC_percentile, x = value, fill = MPL_BC_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on DGF risk (odds ratio)", 
         y = 'Percentile of aCL IgM value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(1/300, 1000)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(xseq),
                     labels = c("1/64", "1/8", "1", "8", "64", '512')) +
  
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Odds ratio: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Odds ratio: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Odds ratio: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

7.2.3.1 Figure merged

Open code
plotac <- 'sup_figure_3'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 4: Anti-cardiolipin IgM modulates infliximab effect on delayed graft function. (A) Predicted DGF risk by anti-cardiolipin IgM for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regiond) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of cardiolipin levels. (B) Posterior distribution for the average effect (odds ratio) of doubling anti-cardiolipin IgM on DGF risk. (C) Posterior distribution of the infliximab effect (odds ratio) on DGF risk across anti-cardiolipin IgM percentiles. Results are from a multivariable Bayesian logistic model with B-splines.

8 Infection models

8.1 Infection by GPE_dep

8.1.1 Priors

8.1.1.1 Main effects model

Open code
priors_main <- c(
  create_prior("IGPE_dep_log2P2",
    2 / sd(data_model_priorImpute$GPE_dep_log2, na.rm = TRUE),
    coef = "IGPE_dep_log2P2"
  ),
   create_prior("IHLA_MMM5",
    2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
    class = "Intercept"
  )
)

8.1.1.2 Non-linear penalized interaction model

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
               coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
               coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
               coef = "IKDPIM50"),
  create_prior("ICITM15",
               2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
               coef = "ICITM15"),
  create_prior("male_sex",
               4,
               coef = "male_sex"),
  create_prior("perfusion_event",
               4,
               coef = "perfusion_event"),
  create_prior("male_sex_donor",
               4,
               coef = "male_sex_donor"),
  
  create_prior("infliximab",
               4,
               coef = "infliximab"),

 set_prior("student_t(3, 0, 0.6)", class = "sds", 
           coef = 's(I(GPE_dep_log2 + 2), bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 0.3)", class = "sds",  
           coef = 's(I(GPE_dep_log2 + 2), by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
            class = "Intercept")
)

8.1.2 Models

8.1.2.1 Main effects models

Open code
model_infection_any_GPE_dep_main <- run(
  expr = brm_multiple(
    infection_any ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      I(GPE_dep_log2 + 2),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_main,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_infection_any_GPE_dep_main",
  reuse = TRUE
)

summary(model_infection_any_GPE_dep_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(GPE_dep_log2 + 2) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          -1.20      0.47    -2.17    -0.30 1.03     8357    25111
## male_sex            0.28      0.36    -0.43     1.01 1.01    35581    26492
## Irec_ageM50        -0.03      0.02    -0.06     0.01 1.01    34812    27578
## male_sex_donor      0.22      0.36    -0.48     0.92 1.01    35747    27955
## IKDPIM50            0.03      0.01     0.02     0.05 1.00    31156    26870
## ICITM15            -0.10      0.03    -0.16    -0.04 1.01    21925    27001
## IHLA_MMM5          -0.27      0.13    -0.53    -0.04 1.05     3743    18243
## perfusion_event    -0.04      0.40    -0.83     0.74 1.07     2925    12861
## infliximab          0.40      0.35    -0.27     1.09 1.01    36151    28346
## IGPE_dep_log2P2    -0.55      0.28    -1.11    -0.02 1.01    35008    27707
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_infection_any_GPE_dep_main)
##                           prior     class            coef group resp dpar nlpar
##                          (flat)         b                                      
##    normal(0, 0.280307006032291)         b         ICITM15                      
##     normal(0, 3.05433848490195)         b IGPE_dep_log2P2                      
##     normal(0, 1.38219051128263)         b       IHLA_MMM5                      
##   normal(0, 0.0970980394231448)         b        IKDPIM50                      
##                    normal(0, 4)         b      infliximab                      
##    normal(0, 0.190589762164436)         b     Irec_ageM50                      
##                    normal(0, 4)         b        male_sex                      
##                    normal(0, 4)         b  male_sex_donor                      
##                    normal(0, 4)         b perfusion_event                      
##  normal(-0.307484699747961, 10) Intercept                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user

tr <- round(exp(fixef(model_infection_any_GPE_dep_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)
Table 12: Results from multivariable Bayesian logistic regression models examining the main effects of predictors, including infliximab treatment and log2-transformed co-factor-dependent phosphatidylethanolamine IgG (GPE_dep_log2), on infection risk, without interaction terms. The odds ratio (OR) represents the estimated change in the odds of infection per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
OR Q2.5 Q97.5
male_sex 1.32 0.65 2.76
Irec_ageM50 0.97 0.94 1.01
male_sex_donor 1.24 0.62 2.51
IKDPIM50 1.03 1.02 1.05
ICITM15 0.91 0.86 0.96
IHLA_MMM5 0.76 0.59 0.97
perfusion_event 0.96 0.44 2.09
infliximab 1.49 0.77 2.97
IGPE_dep_log2P2 0.58 0.33 0.98

8.1.2.2 Non-linear interaction model

Open code
model_infection_any_GPE_dep_interaction_NL <- run(
  expr = brm_multiple(
    infection_any ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(I(GPE_dep_log2+2), bs = 'ps', k = 5) +
    s(I(GPE_dep_log2+2), by = infliximab, bs = 'ps', k = 5),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_infection_any_GPE_dep_interaction_NL",
  reuse = TRUE
)

summary(model_infection_any_GPE_dep_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
## Warning: There were 1 divergent transitions after warmup. Increasing
## adapt_delta above 0.95 may help. See
## http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(GPE_dep_log2 + 2), bs = "ps", k = 5) + s(I(GPE_dep_log2 + 2), by = infliximab, bs = "ps", k = 5) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Smoothing Spline Hyperparameters:
##                                   Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIGPE_dep_log2P2_1)               0.39      0.36     0.02     1.78 1.01
## sds(sIGPE_dep_log2P2infliximab_1)     0.22      0.21     0.01     1.20 1.00
##                                   Bulk_ESS Tail_ESS
## sds(sIGPE_dep_log2P2_1)              23011    16212
## sds(sIGPE_dep_log2P2infliximab_1)    29739    16611
## 
## Regression Coefficients:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                        -0.96      0.47    -1.89    -0.05 1.02
## male_sex                          0.20      0.37    -0.53     0.93 1.01
## Irec_ageM50                      -0.03      0.02    -0.06     0.01 1.01
## male_sex_donor                    0.15      0.36    -0.57     0.87 1.01
## IKDPIM50                          0.03      0.01     0.01     0.05 1.01
## ICITM15                          -0.10      0.03    -0.16    -0.04 1.01
## IHLA_MMM5                        -0.27      0.12    -0.53    -0.03 1.05
## perfusion_event                   0.02      0.41    -0.77     0.83 1.07
## infliximab                        0.01      3.96    -7.77     7.88 1.02
## sIGPE_dep_log2P2_1               -0.01      1.21    -2.46     2.72 1.01
## sIGPE_dep_log2P2:infliximab_1    -1.54      2.40    -6.31     3.14 1.02
## sIGPE_dep_log2P2:infliximab_2     1.73      1.92    -2.01     5.47 1.01
##                               Bulk_ESS Tail_ESS
## Intercept                        10823    27696
## male_sex                         35504    26209
## Irec_ageM50                      34966    27068
## male_sex_donor                   36837    27583
## IKDPIM50                         33808    25857
## ICITM15                          17002    25866
## IHLA_MMM5                         3867    19114
## perfusion_event                   2911    11736
## infliximab                       12595    17936
## sIGPE_dep_log2P2_1               24856    21147
## sIGPE_dep_log2P2:infliximab_1    14000    20327
## sIGPE_dep_log2P2:infliximab_2    14554    20883
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_infection_any_GPE_dep_interaction_NL)
##                           prior     class
##                          (flat)         b
##    normal(0, 0.280307006032291)         b
##     normal(0, 1.38219051128263)         b
##   normal(0, 0.0970980394231448)         b
##                    normal(0, 4)         b
##    normal(0, 0.190589762164436)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                          (flat)         b
##                          (flat)         b
##                          (flat)         b
##  normal(-0.307484699747961, 10) Intercept
##            student_t(3, 0, 2.5)       sds
##            student_t(3, 0, 0.6)       sds
##            student_t(3, 0, 0.3)       sds
##                                                       coef group resp dpar
##                                                                           
##                                                    ICITM15                
##                                                  IHLA_MMM5                
##                                                   IKDPIM50                
##                                                 infliximab                
##                                                Irec_ageM50                
##                                                   male_sex                
##                                             male_sex_donor                
##                                            perfusion_event                
##                                         sIGPE_dep_log2P2_1                
##                              sIGPE_dep_log2P2:infliximab_1                
##                              sIGPE_dep_log2P2:infliximab_2                
##                                                                           
##                                                                           
##                   s(I(GPE_dep_log2 + 2), bs = "ps", k = 5)                
##  s(I(GPE_dep_log2 + 2), by = infliximab, bs = "ps", k = 5)                
##  nlpar lb ub       source
##                   default
##                      user
##                      user
##                      user
##                      user
##                      user
##                      user
##                      user
##                      user
##              (vectorized)
##              (vectorized)
##              (vectorized)
##                      user
##         0         default
##         0            user
##         0            user

tr2 <- round(exp(fixef(model_infection_any_GPE_dep_interaction_NL, 
                       robust = TRUE)[-c(1,9:12), c(1,3,4)]), 3)

antibody_seq <- quantile(data_model_priorImpute$GPE_dep_log2, 
                         probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPE_dep_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_infection_any_GPE_dep_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get odds ratio for infliximab effect across antibody values
prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()
names(prediction) <- c('p05', 'p95')

infliximab_GPE_dep_log2_int <- quantile(
  exp((log(prediction$p95) - log(prediction$p05))/scaling_unit), 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_GPE_dep_log2_int, 3))
row.names(tr2)[8] <- 'infliximab:GPE_dep_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)
Table 13: Results from multivariable Bayesian logistic regression models incorporating a non-linear interaction between co-factor-dependent phosphatidylethanolamine IgG (aPE-dep IgG, GPE_dep_log2) and infliximab treatment on infection risk, while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of aPE-dep IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
(R)OR Q2.5 Q97.5
male_sex 1.220 0.590 2.539
Irec_ageM50 0.972 0.938 1.006
male_sex_donor 1.166 0.568 2.392
IKDPIM50 1.034 1.015 1.054
ICITM15 0.905 0.851 0.957
IHLA_MMM5 0.763 0.589 0.969
perfusion_event 1.018 0.463 2.299
infliximab:GPE_dep_log2 0.097 0.008 0.995

8.1.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_model_priorImpute$GPE_dep_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPE_dep_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_infection_any_GPE_dep_interaction_NL,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')), 
  GPE_dep_log2 = data_prediction$GPE_dep_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control"))) %>% 
  ggplot(aes(x = GPE_dep_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 1),
                     breaks = c(seq(0, 1, by = 0.2))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  labs(x = expression(log[2]~"(aPE IgG dep [OD])"), y = "Infection risk") +
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") +
  
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 0),
    aes(x = GPE_dep_log2),
    sides = "b",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  ) +
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 1),
    aes(x = GPE_dep_log2),
     sides = "t",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  )  + 
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##         0%       100% 
## -3.6438562  0.4162993

tr <-  posterior_epred(
    model_infection_any_GPE_dep_interaction_NL,
    newdata = data_prediction)

tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)])) /
  (antibody_seq[2] - antibody_seq[1])
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_GPE_dep_log2 = tr_ctrl,
  b_GPE_dep_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = exp(b_GPE_dep_log2), 
         infliximab = exp(b_GPE_dep_log2_infliximab)) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##       control infliximab
## 2.5%     0.44       0.11
## 97.5%    2.37       0.79
## 50%      0.99       0.32
## 0.1%     0.27       0.05
## 99.9%    4.28       1.33

xpos <- 10

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aPE IgG dep on infection risk (OR)", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(1/20, 20)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(1/16, 1/4, 1, 4 ,16),
                     labels = c("1/16", "1/4", "1", "4", "16")) +
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
##        5%       25%       50%       75%       95% 
## -3.134163 -2.666576 -2.392137 -2.005782 -1.039488

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPE_dep_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_infection_any_GPE_dep_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()


names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')


CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% round(3)

CIS
##          p05   p25   p50   p75   p95
## 2.5%   1.147 1.005 0.824 0.492 0.066
## 97.5% 12.692 5.193 3.466 2.425 1.754
## 50%    3.731 2.260 1.676 1.097 0.361
## 0.1%   0.588 0.657 0.561 0.310 0.023
## 99.9% 24.985 8.400 5.455 3.839 4.295

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'GPE_dep_percentile') %>% 
  
  ggplot(aes(y = GPE_dep_percentile, x = value, fill = GPE_dep_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on infection risk (odds ratio)", 
         y = 'Percentile of aPE IgG dep value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(1/300, 1000)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(xseq),
                     labels = c("1/64", "1/8", "1", "8", "64", '512')) +
  
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
    annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Odds ratio: ", round(CIS[3,5], 2)),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Odds ratio: ", round(CIS[3,4], 2)),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Odds ratio: ", round(CIS[3,3], 2)),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Odds ratio: ", round(CIS[3,2],2 )),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Odds ratio: ", round(CIS[3,1], 2)),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", round(CIS[1,5], 2), ", ", 
                          round(CIS[2,5], 2), "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", round(CIS[1,4], 2), ", ", 
                          round(CIS[2,4], 2), "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", round(CIS[1,3], 2), ", ", 
                          round(CIS[2,3], 2), "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", round(CIS[2,2], 2), "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", round(CIS[1,1], 2), ", ", 
                          round(CIS[2,1], 2), "]"),
           color = cole[1] ) 

8.1.3.1 Figure merged

Open code
plotac <- 'sup_figure_7'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 5: Co-factor dependent anti-phosphatidylethanolamine IgG (aPE-dep IgG) modulates the effect of infliximab on infection risk (A) Predicted infection risk by aPE-dep IgG for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regions) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of aPE-dep IgG levels. (B) Posterior distribution for the average effect of doubling aPE-dep IgG on infection risk (odds ratio). (C) Posterior distribution of the effect of infliximab (odds ratio) on infection risk across aPE-dep IgG percentiles. Results are from a multivariable Bayesian logistic model with B-splines.

8.2 Infection by GPE_ind

8.2.1 Priors

8.2.1.1 Main effects model

Open code
priors_main <- c(
  create_prior("IGPE_ind_log2P3",
    2 / sd(data_model_priorImpute$GPE_ind_log2, na.rm = TRUE),
    coef = "IGPE_ind_log2P3"
  ),
   create_prior("IHLA_MMM5",
    2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
    class = "Intercept"
  )
)

8.2.1.2 Non-linear penalized interaction model

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
               coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
               coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
               coef = "IKDPIM50"),
  create_prior("ICITM15",
               2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
               coef = "ICITM15"),
  create_prior("male_sex",
               4,
               coef = "male_sex"),
  create_prior("perfusion_event",
               4,
               coef = "perfusion_event"),
  create_prior("male_sex_donor",
               4,
               coef = "male_sex_donor"),
  
  create_prior("infliximab",
               4,
               coef = "infliximab"),

 set_prior("student_t(3, 0, 0.6)", class = "sds", 
           coef = 's(I(GPE_ind_log2 + 3), bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 0.3)", class = "sds",  
           coef = 's(I(GPE_ind_log2 + 3), by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$infection_any)), ", 10)"),
            class = "Intercept")
)

8.2.2 Models

8.2.2.1 Main effects models

Open code
model_infection_any_GPE_ind_main <- run(
  expr = brm_multiple(
    infection_any ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      I(GPE_ind_log2 + 3),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_main,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_infection_any_GPE_ind_main",
  reuse = TRUE
)

summary(model_infection_any_GPE_ind_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(GPE_ind_log2 + 3) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          -0.98      0.45    -1.90    -0.12 1.02    11019    25593
## male_sex            0.27      0.36    -0.44     1.00 1.01    37004    28448
## Irec_ageM50        -0.02      0.02    -0.06     0.01 1.01    35806    28429
## male_sex_donor      0.21      0.36    -0.48     0.92 1.01    36893    27040
## IKDPIM50            0.03      0.01     0.01     0.05 1.01    33713    27071
## ICITM15            -0.09      0.03    -0.15    -0.04 1.01    20286    25862
## IHLA_MMM5          -0.27      0.12    -0.52    -0.03 1.05     4283    14455
## perfusion_event    -0.00      0.40    -0.79     0.80 1.07     2779    11061
## infliximab          0.33      0.35    -0.34     1.03 1.01    35569    27304
## IGPE_ind_log2P3    -0.42      0.25    -0.94     0.04 1.01    39171    26823
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_infection_any_GPE_ind_main)
##                           prior     class            coef group resp dpar nlpar
##                          (flat)         b                                      
##    normal(0, 0.280307006032291)         b         ICITM15                      
##     normal(0, 2.72256264350783)         b IGPE_ind_log2P3                      
##     normal(0, 1.38219051128263)         b       IHLA_MMM5                      
##   normal(0, 0.0970980394231448)         b        IKDPIM50                      
##                    normal(0, 4)         b      infliximab                      
##    normal(0, 0.190589762164436)         b     Irec_ageM50                      
##                    normal(0, 4)         b        male_sex                      
##                    normal(0, 4)         b  male_sex_donor                      
##                    normal(0, 4)         b perfusion_event                      
##  normal(-0.307484699747961, 10) Intercept                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user

tr <- round(exp(fixef(model_infection_any_GPE_ind_main, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)
Table 14: Results from multivariable Bayesian logistic regression models examining the main effects of predictors, including infliximab treatment and log2-transformed co-factor-independent phosphatidylethanolamine IgG (GPE_ind_log2), on infection risk, without interaction terms. The odds ratio (OR) represents the estimated change in the odds of infection per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
OR Q2.5 Q97.5
male_sex 1.32 0.64 2.71
Irec_ageM50 0.98 0.94 1.01
male_sex_donor 1.23 0.62 2.51
IKDPIM50 1.03 1.01 1.05
ICITM15 0.91 0.86 0.96
IHLA_MMM5 0.77 0.59 0.97
perfusion_event 1.00 0.45 2.23
infliximab 1.39 0.71 2.79
IGPE_ind_log2P3 0.66 0.39 1.05

8.2.2.2 Non-linear interaction model

Open code
model_infection_any_GPE_ind_interaction_NL <- run(
  expr = brm_multiple(
    infection_any ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(I(GPE_ind_log2+3), bs = 'ps', k = 5) +
    s(I(GPE_ind_log2+3), by = infliximab, bs = 'ps', k = 5),
    family = bernoulli(),
    data = data_imputed,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_infection_any_GPE_ind_interaction_NL",
  reuse = TRUE
)

summary(model_infection_any_GPE_ind_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: infection_any ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(GPE_ind_log2 + 3), bs = "ps", k = 5) + s(I(GPE_ind_log2 + 3), by = infliximab, bs = "ps", k = 5) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Smoothing Spline Hyperparameters:
##                                   Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIGPE_ind_log2P3_1)               0.36      0.33     0.02     1.69 1.01
## sds(sIGPE_ind_log2P3infliximab_1)     0.22      0.21     0.01     1.14 1.00
##                                   Bulk_ESS Tail_ESS
## sds(sIGPE_ind_log2P3_1)              20777    16750
## sds(sIGPE_ind_log2P3infliximab_1)    29345    15825
## 
## Regression Coefficients:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                        -1.01      0.47    -1.96    -0.12 1.03
## male_sex                          0.23      0.37    -0.49     0.97 1.01
## Irec_ageM50                      -0.02      0.02    -0.06     0.01 1.01
## male_sex_donor                    0.20      0.36    -0.51     0.91 1.01
## IKDPIM50                          0.03      0.01     0.01     0.05 1.01
## ICITM15                          -0.10      0.03    -0.16    -0.04 1.01
## IHLA_MMM5                        -0.27      0.13    -0.54    -0.03 1.05
## perfusion_event                   0.06      0.42    -0.77     0.89 1.07
## infliximab                        0.02      3.94    -7.59     7.86 1.02
## sIGPE_ind_log2P3_1               -0.00      0.94    -2.19     1.95 1.01
## sIGPE_ind_log2P3:infliximab_1    -1.90      2.38    -6.69     2.67 1.02
## sIGPE_ind_log2P3:infliximab_2     2.02      2.37    -2.61     6.62 1.02
##                               Bulk_ESS Tail_ESS
## Intercept                         9152    25359
## male_sex                         35120    26888
## Irec_ageM50                      33206    26289
## male_sex_donor                   34551    26083
## IKDPIM50                         32183    26588
## ICITM15                          16827    25092
## IHLA_MMM5                         3866    13123
## perfusion_event                   2824    11080
## infliximab                       12055    17429
## sIGPE_ind_log2P3_1               25340    18221
## sIGPE_ind_log2P3:infliximab_1    13678    20478
## sIGPE_ind_log2P3:infliximab_2    13739    20092
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_infection_any_GPE_ind_interaction_NL)
##                           prior     class
##                          (flat)         b
##    normal(0, 0.280307006032291)         b
##     normal(0, 1.38219051128263)         b
##   normal(0, 0.0970980394231448)         b
##                    normal(0, 4)         b
##    normal(0, 0.190589762164436)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                          (flat)         b
##                          (flat)         b
##                          (flat)         b
##  normal(-0.307484699747961, 10) Intercept
##            student_t(3, 0, 2.5)       sds
##            student_t(3, 0, 0.6)       sds
##            student_t(3, 0, 0.3)       sds
##                                                       coef group resp dpar
##                                                                           
##                                                    ICITM15                
##                                                  IHLA_MMM5                
##                                                   IKDPIM50                
##                                                 infliximab                
##                                                Irec_ageM50                
##                                                   male_sex                
##                                             male_sex_donor                
##                                            perfusion_event                
##                                         sIGPE_ind_log2P3_1                
##                              sIGPE_ind_log2P3:infliximab_1                
##                              sIGPE_ind_log2P3:infliximab_2                
##                                                                           
##                                                                           
##                   s(I(GPE_ind_log2 + 3), bs = "ps", k = 5)                
##  s(I(GPE_ind_log2 + 3), by = infliximab, bs = "ps", k = 5)                
##  nlpar lb ub       source
##                   default
##                      user
##                      user
##                      user
##                      user
##                      user
##                      user
##                      user
##                      user
##              (vectorized)
##              (vectorized)
##              (vectorized)
##                      user
##         0         default
##         0            user
##         0            user

tr2 <- round(exp(fixef(model_infection_any_GPE_ind_interaction_NL, 
                       robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)

antibody_seq <- quantile(data_model_priorImpute$GPE_ind_log2, 
                         probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPE_ind_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_infection_any_GPE_ind_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get odds ratio for infliximab effect across antibody values
prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()
names(prediction) <- c('p05', 'p95')

infliximab_GPE_ind_log2_int <- quantile(
  exp((log(prediction$p95) - log(prediction$p05))/scaling_unit), 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_GPE_ind_log2_int, 4))
row.names(tr2)[8] <- 'infliximab:GPE_ind_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)
Table 15: Results from multivariable Bayesian logistic regression models incorporating a non-linear interaction between co-factor-independent phosphatidylethanolamine IgG (aPE-ind IgG, GPE_ind_log2) and infliximab treatment on infection risk, while accounting for other covariates. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of aPE-ind IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
(R)OR Q2.5 Q97.5
male_sex 1.2600 0.610 2.6400
Irec_ageM50 0.9800 0.940 1.0100
male_sex_donor 1.2200 0.600 2.4900
IKDPIM50 1.0300 1.010 1.0500
ICITM15 0.9100 0.850 0.9600
IHLA_MMM5 0.7600 0.590 0.9700
perfusion_event 1.0600 0.460 2.4300
infliximab:GPE_ind_log2 0.0751 0.005 0.7543

8.2.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_model_priorImpute$GPE_ind_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPE_ind_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_infection_any_GPE_ind_interaction_NL,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')), 
  GPE_ind_log2 = data_prediction$GPE_ind_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control"))) %>% 
  ggplot(aes(x = GPE_ind_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 1),
                     breaks = c(seq(0, 1, by = 0.2))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  labs(x = expression(log[2]~"(aPE IgG ind [OD])"), y = "Infection risk") +
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") +
  
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 0),
    aes(x = GPE_ind_log2),
    sides = "b",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  ) +
  geom_rug(
    data = data_model_priorImpute %>% filter(DGF == 1),
    aes(x = GPE_ind_log2),
     sides = "t",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  )  + 
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##          0%        100% 
## -3.86775220 -0.03283139

tr <-  posterior_epred(
    model_infection_any_GPE_ind_interaction_NL,
    newdata = data_prediction)

tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)])) /
  (antibody_seq[2] - antibody_seq[1])
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_GPE_ind_log2 = tr_ctrl,
  b_GPE_ind_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = exp(b_GPE_ind_log2), 
         infliximab = exp(b_GPE_ind_log2_infliximab)) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##       control infliximab
## 2.5%     0.53       0.09
## 97.5%    1.91       0.75
## 50%      1.02       0.30
## 0.1%     0.35       0.03
## 99.9%    2.76       1.17

xpos <- 10

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aPE IgG ind on infection risk (OR)", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(1/20, 20)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(1/16, 1/4, 1, 4 ,16),
                     labels = c("1/16", "1/4", "1", "4", "16")) +
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
##        5%       25%       50%       75%       95% 
## -3.654722 -3.411195 -3.164884 -2.708396 -1.490602

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPE_ind_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_infection_any_GPE_ind_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()


names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##         p05  p25  p50  p75  p95
## 2.5%   1.11 1.01 0.85 0.45 0.03
## 97.5%  9.08 5.56 3.68 2.26 1.33
## 50%    3.12 2.34 1.75 1.02 0.23
## 0.1%   0.63 0.65 0.57 0.27 0.01
## 99.9% 16.77 9.12 5.86 3.60 3.26

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'GPE_ind_percentile') %>% 
  
  ggplot(aes(y = GPE_ind_percentile, x = value, fill = GPE_ind_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on infection risk (odds ratio)", 
         y = 'Percentile of aPE IgG ind value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(1/300, 1000)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(xseq),
                     labels = c("1/64", "1/8", "1", "8", "64", '512')) +
  
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Odds ratio: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Odds ratio: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Odds ratio: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

8.2.3.1 Figure merged

Open code
plotac <- 'sup_figure_8'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 6: Co-factor independent anti-phosphatidylethanolamine IgG (aPE-ind IgG) modulates the effect of infliximab on infection risk (A) Predicted infection risk by aPE-dep IgG for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regions) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of aPE-ind IgG levels. (B) Posterior distribution for the average effect of doubling aPE-ind IgG on infection risk (odds ratio). (C) Posterior distribution of the effect of infliximab (odds ratio) on infection risk across aPE-ind IgG percentiles. Results are from a multivariable Bayesian logistic model with B-splines.

9 GFR models

9.1 GFR_MDRD by GPL_BC

9.1.1 Priors

Open code

GFR_sd <- sd(data_model_priorImpute$GFR_MDRD)
GFR_sd
## [1] 20.25757

9.1.1.1 Main effects model

Open code
priors_main <- c(
  create_prior("GPL_BC_log2",
    GFR_sd*(2*GFR_sd) / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
    coef = "GPL_BC_log2"
  ),
   create_prior("IHLA_MMM5",
    (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4*GFR_sd,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4*GFR_sd,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4*GFR_sd,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4*GFR_sd,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD), ", 200)"),
    class = "Intercept"
  )
)

9.1.1.2 Non-linear penalized interaction model

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"),
  create_prior("ICITM15",
               (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"),
  create_prior("male_sex",
    4*GFR_sd,
    coef = "male_sex"),
  create_prior("perfusion_event",
    4*GFR_sd,
    coef = "perfusion_event"),
  create_prior("male_sex_donor",
    4*GFR_sd,
    coef = "male_sex_donor"),
  
  create_prior("infliximab",
    4*GFR_sd,
    coef = "infliximab"),

 set_prior("student_t(3, 0, 12)", class = "sds", 
           coef = 's(GPL_BC_log2, bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 6)", class = "sds",  
           coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD), ", 200)"),
            class = "Intercept")
)

9.1.2 Models

9.1.2.1 Main effects models

Open code
model_GFR_MDRD_GPL_BC_main <- run(
  expr = brm_multiple(
    GFR_MDRD ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      GPL_BC_log2,
    family = student(),
    data = data_imputed,
    prior = priors_main,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_GPL_BC_main",
  reuse = TRUE
)

summary(model_GFR_MDRD_GPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          54.68      3.91    46.96    62.35 1.01    24831    27184
## male_sex           -1.55      3.16    -7.77     4.77 1.01    37765    27484
## Irec_ageM50         0.06      0.15    -0.23     0.34 1.01    36648    28073
## male_sex_donor      1.35      3.10    -4.77     7.48 1.01    36660    26964
## IKDPIM50           -0.19      0.08    -0.34    -0.04 1.01    35386    27634
## ICITM15             0.23      0.22    -0.21     0.66 1.02    11422    26910
## IHLA_MMM5          -0.97      1.07    -3.11     1.11 1.06     3180    13261
## perfusion_event    -5.76      3.35   -12.35     0.80 1.06     3549    13194
## infliximab         -2.45      3.02    -8.43     3.38 1.01    37369    28011
## GPL_BC_log2         0.60      1.08    -1.52     2.67 1.01    36026    27839
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    18.53      1.23    16.10    21.01 1.01    31215    24031
## nu       18.84     10.62     6.38    55.52 1.00    32368    25991
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_GFR_MDRD_GPL_BC_main)
##                         prior     class            coef group resp dpar nlpar
##                        (flat)         b                                      
##   normal(0, 579.319999877126)         b     GPL_BC_log2                      
##   normal(0, 5.67833744497037)         b         ICITM15                      
##   normal(0, 27.9998143727979)         b       IHLA_MMM5                      
##   normal(0, 1.96696986241627)         b        IKDPIM50                      
##   normal(0, 81.0302607180105)         b      infliximab                      
##   normal(0, 3.86088452959197)         b     Irec_ageM50                      
##   normal(0, 81.0302607180105)         b        male_sex                      
##   normal(0, 81.0302607180105)         b  male_sex_donor                      
##   normal(0, 81.0302607180105)         b perfusion_event                      
##  normal(51.900395480226, 200) Intercept                                      
##                 gamma(2, 0.1)        nu                                      
##           student_t(3, 0, 18)     sigma                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##   1    default
##   0    default

tr <- round(fixef(model_GFR_MDRD_GPL_BC_main, robust = TRUE)[-1, c(1,3,4)], 2)
colnames(tr)[1] <- 'Estimate'
kableExtra::kable(tr)
Table 16: Results from multivariable Bayesian robust regression model examining the main effects of predictors, including infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on estimated glomerular filtration rate (eGFR, GFR_MDRD), without interaction terms. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
Estimate Q2.5 Q97.5
male_sex -1.55 -7.77 4.77
Irec_ageM50 0.06 -0.23 0.34
male_sex_donor 1.35 -4.77 7.48
IKDPIM50 -0.19 -0.34 -0.04
ICITM15 0.23 -0.21 0.66
IHLA_MMM5 -0.97 -3.11 1.11
perfusion_event -5.76 -12.35 0.80
infliximab -2.45 -8.43 3.38
GPL_BC_log2 0.60 -1.52 2.67

9.1.2.2 Non-linear interaction model

Open code
model_GFR_MDRD_GPL_BC_interaction_NL <- run(
  expr = brm_multiple(
    GFR_MDRD ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(GPL_BC_log2, bs = 'ps', k = 5) +
    s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
    family = student(),
    data = data_imputed,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_GPL_BC_interaction_NL",
  reuse = TRUE
)

summary(model_GFR_MDRD_GPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Smoothing Spline Hyperparameters:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1)               9.59      6.65     0.79    32.62 1.01
## sds(sGPL_BC_log2infliximab_1)     4.22      3.92     0.20    19.87 1.00
##                               Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1)              17186    13787
## sds(sGPL_BC_log2infliximab_1)    34106    17300
## 
## Regression Coefficients:
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                    55.59      3.87    47.89    63.25 1.01    34127
## male_sex                     -2.13      3.12    -8.38     4.01 1.01    45929
## Irec_ageM50                   0.05      0.14    -0.23     0.33 1.01    45812
## male_sex_donor                0.08      3.13    -6.08     6.23 1.01    43251
## IKDPIM50                     -0.19      0.08    -0.35    -0.04 1.01    40749
## ICITM15                       0.23      0.22    -0.20     0.65 1.02    10278
## IHLA_MMM5                    -1.19      1.06    -3.27     0.86 1.07     3216
## perfusion_event              -5.52      3.35   -11.93     1.03 1.05     4240
## infliximab                    1.75     79.08  -154.92   156.04 1.01    13750
## sGPL_BC_log2_1               18.26     13.84   -11.91    55.94 1.01    24018
## sGPL_BC_log2:infliximab_1   -19.27     45.54  -107.83    71.48 1.01    14101
## sGPL_BC_log2:infliximab_2    13.44     28.08   -41.91    69.30 1.01    14185
##                           Tail_ESS
## Intercept                    28929
## male_sex                     25866
## Irec_ageM50                  27262
## male_sex_donor               27173
## IKDPIM50                     28218
## ICITM15                      26370
## IHLA_MMM5                    13665
## perfusion_event              18675
## infliximab                   19279
## sGPL_BC_log2_1               19589
## sGPL_BC_log2:infliximab_1    19727
## sGPL_BC_log2:infliximab_2    19762
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    18.01      1.22    15.59    20.53 1.01    35929    26058
## nu       17.93     10.20     6.13    52.20 1.00    37566    27925
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_GFR_MDRD_GPL_BC_interaction_NL)
##                         prior     class
##                        (flat)         b
##   normal(0, 5.67833744497037)         b
##   normal(0, 27.9998143727979)         b
##   normal(0, 1.96696986241627)         b
##   normal(0, 81.0302607180105)         b
##   normal(0, 3.86088452959197)         b
##   normal(0, 81.0302607180105)         b
##   normal(0, 81.0302607180105)         b
##   normal(0, 81.0302607180105)         b
##                        (flat)         b
##                        (flat)         b
##                        (flat)         b
##  normal(51.900395480226, 200) Intercept
##                 gamma(2, 0.1)        nu
##           student_t(3, 0, 18)       sds
##           student_t(3, 0, 12)       sds
##            student_t(3, 0, 6)       sds
##           student_t(3, 0, 18)     sigma
##                                               coef group resp dpar nlpar lb ub
##                                                                               
##                                            ICITM15                            
##                                          IHLA_MMM5                            
##                                           IKDPIM50                            
##                                         infliximab                            
##                                        Irec_ageM50                            
##                                           male_sex                            
##                                     male_sex_donor                            
##                                    perfusion_event                            
##                                     sGPL_BC_log2_1                            
##                          sGPL_BC_log2:infliximab_1                            
##                          sGPL_BC_log2:infliximab_2                            
##                                                                               
##                                                                           1   
##                                                                           0   
##                   s(GPL_BC_log2, bs = "ps", k = 5)                        0   
##  s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)                        0   
##                                                                           0   
##        source
##       default
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##  (vectorized)
##  (vectorized)
##  (vectorized)
##          user
##       default
##       default
##          user
##          user
##       default

tr2 <- round(fixef(model_GFR_MDRD_GPL_BC_interaction_NL, 
                       robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)

antibody_seq <- quantile(data_model_priorImpute$GPL_BC_log2, 
                         probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get Estimate for infliximab effect across antibody values
prediction <- (
  prediction_infliximab-
     prediction_ctrl
  ) %>% data.frame()

names(prediction) <- c('p05', 'p95')

infliximab_GPL_BC_log2_int <- quantile(
  (prediction$p95 - prediction$p05)/scaling_unit, 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
kableExtra::kable(tr2)
Table 17: Results from a multivariable Bayesian robust regression model incorporating a non-linear interaction between anti-cardiolipin IgG (GPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR, GFR_MDRD), while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:GPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
Estimate Q2.5 Q97.5
male_sex -2.13 -8.38 4.01
Irec_ageM50 0.05 -0.23 0.33
male_sex_donor 0.08 -6.08 6.23
IKDPIM50 -0.19 -0.35 -0.04
ICITM15 0.23 -0.20 0.65
IHLA_MMM5 -1.19 -3.27 0.86
perfusion_event -5.52 -11.93 1.03
infliximab:GPL_BC_log2 -25.18 -43.66 -6.75

9.1.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_model_priorImpute$GPL_BC_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
  GPL_BC_log2 = data_prediction$GPL_BC_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control")), 
         `Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>% 
  ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 125),
                      breaks = c(seq(0, 125, by = 25))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  geom_point(data = data_model_priorImpute, 
             aes(x = GPL_BC_log2, y = GFR_MDRD, col = group, fill = group)) +
  
  labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"), 
       y = "GFR (mL/min/1.73 m²)") +
  
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size = 10),
        axis.title=element_text(size = 12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") + 
  
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##        0%      100% 
## -3.861561  4.949819

tr <-  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL,
    newdata = data_prediction)

tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)]) /
  (antibody_seq[2] - antibody_seq[1])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_GPL_BC_log2 = tr_ctrl,
  b_GPL_BC_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = b_GPL_BC_log2, 
         infliximab = b_GPL_BC_log2_infliximab) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##       control infliximab
## 2.5%    -0.03      -6.95
## 97.5%    5.72       1.14
## 50%      2.82      -2.95
## 0.1%    -1.60      -9.80
## 99.9%    7.62       4.11

xpos <- 20

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aCL IgG on GFR (mL/min/1.73 m²)", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(-20, 26)) +
  
  geom_vline(xintercept = 0, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Estimate: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Estimate: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  prediction_infliximab-
     prediction_ctrl
  ) %>% data.frame()


names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(1)

CIS
##        p05  p25   p50   p75   p95
## 2.5%  -2.4 -4.8  -7.7 -14.1 -30.0
## 97.5% 17.9  8.8   4.5  -0.3  -5.1
## 50%    7.7  2.0  -1.7  -7.2 -17.4
## 0.1%  -8.2 -9.1 -11.3 -18.0 -38.0
## 99.9% 23.8 13.0   8.3   3.6   2.0

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'GPL_BC_percentile') %>% 
  
  ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)", 
         y = 'Percentile of aCL IgG value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(-40, 40)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  
  
  geom_vline(xintercept = 0, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Estimate: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Estimate: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Estimate: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Estimate: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Estimate: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

9.1.3.1 Figure merged

Open code
plotac <- 'sup_figure_4'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 7: Anti-cardiolipin IgG modulates the effect of infliximab on estimated glomerular filtration rate (eGFR). (A) Predicted eGFR by anti-cardiolipin IgG for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regions) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of cardiolipin levels. (B) Posterior distribution of the average effect of doubling anti-cardiolipin IgG on eGFR. (C) Posterior distribution of the effect of infliximab on eGFR across anti-cardiolipin IgG percentiles. Results are from a multivariable Bayesian robust regression with B-splines.

9.2 GFR_MDRD by MPL_BC

9.2.1 Priors

9.2.1.1 Main effects model

Open code
priors_main <- c(
  create_prior("IMPL_BC_log2M2",
    (2*GFR_sd) / sd(data_model_priorImpute$MPL_BC_log2, na.rm = TRUE),
    coef = "IMPL_BC_log2M2"
  ),
   create_prior("IHLA_MMM5",
    (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4*GFR_sd,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4*GFR_sd,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4*GFR_sd,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4*GFR_sd,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD), ", 200)"),
    class = "Intercept"
  )
)

9.2.1.2 Non-linear penalized interaction model

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"),
  create_prior("ICITM15",
               (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"),
  create_prior("male_sex",
    4*GFR_sd,
    coef = "male_sex"),
  create_prior("perfusion_event",
    4*GFR_sd,
    coef = "perfusion_event"),
  create_prior("male_sex_donor",
    4*GFR_sd,
    coef = "male_sex_donor"),
  
  create_prior("infliximab",
    4*GFR_sd,
    coef = "infliximab"),

 set_prior("student_t(3, 0, 12)", class = "sds", 
           coef = 's(I(MPL_BC_log2 - 2), bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 6)", class = "sds",  
           coef = 's(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD), ", 200)"),
            class = "Intercept")
)

9.2.2 Models

9.2.2.1 Main effects models

Open code
model_GFR_MDRD_MPL_BC_main <- run(
  expr = brm_multiple(
    GFR_MDRD ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      I(MPL_BC_log2 - 2),
    family = student(),
    data = data_imputed,
    prior = priors_main,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_MPL_BC_main",
  reuse = TRUE
)

summary(model_GFR_MDRD_MPL_BC_main, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + I(MPL_BC_log2 - 2) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          55.75      3.99    47.95    63.59 1.02    15676    27265
## male_sex           -2.00      3.18    -8.29     4.26 1.01    36988    27786
## Irec_ageM50         0.05      0.14    -0.23     0.34 1.01    36377    27272
## male_sex_donor      1.08      3.06    -5.00     7.17 1.01    36948    28496
## IKDPIM50           -0.19      0.08    -0.34    -0.03 1.01    35327    27152
## ICITM15             0.28      0.22    -0.16     0.70 1.02    11620    26888
## IHLA_MMM5          -0.97      1.07    -3.11     1.12 1.06     3340    11461
## perfusion_event    -6.45      3.39   -13.09     0.22 1.05     3818    19112
## infliximab         -3.15      3.07    -9.23     2.93 1.01    37419    27699
## IMPL_BC_log2M2     -0.98      0.99    -2.90     0.98 1.01    36441    28028
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    18.48      1.22    16.08    20.97 1.01    29092    24387
## nu       18.77     10.57     6.44    55.18 1.00    31124    26418
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_GFR_MDRD_MPL_BC_main)
##                         prior     class            coef group resp dpar nlpar
##                        (flat)         b                                      
##   normal(0, 5.67833744497037)         b         ICITM15                      
##   normal(0, 27.9998143727979)         b       IHLA_MMM5                      
##   normal(0, 1.96696986241627)         b        IKDPIM50                      
##   normal(0, 25.9163777815998)         b  IMPL_BC_log2M2                      
##   normal(0, 81.0302607180105)         b      infliximab                      
##   normal(0, 3.86088452959197)         b     Irec_ageM50                      
##   normal(0, 81.0302607180105)         b        male_sex                      
##   normal(0, 81.0302607180105)         b  male_sex_donor                      
##   normal(0, 81.0302607180105)         b perfusion_event                      
##  normal(51.900395480226, 200) Intercept                                      
##                 gamma(2, 0.1)        nu                                      
##           student_t(3, 0, 18)     sigma                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##   1    default
##   0    default

tr <- round(fixef(model_GFR_MDRD_MPL_BC_main, robust = TRUE)[-1, c(1,3,4)], 2)
colnames(tr)[1] <- 'Estimate'
kableExtra::kable(tr)
Table 18: Results from multivariable Bayesian robust regression models examining the main effects of predictors, including infliximab treatment and log2-transformed anti-cardiolipin IgM (MPL_BC_log2), on estimated glomerular filtration rate (eGFR, GFR_MDRD), without interaction terms. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
Estimate Q2.5 Q97.5
male_sex -2.00 -8.29 4.26
Irec_ageM50 0.05 -0.23 0.34
male_sex_donor 1.08 -5.00 7.17
IKDPIM50 -0.19 -0.34 -0.03
ICITM15 0.28 -0.16 0.70
IHLA_MMM5 -0.97 -3.11 1.12
perfusion_event -6.45 -13.09 0.22
infliximab -3.15 -9.23 2.93
IMPL_BC_log2M2 -0.98 -2.90 0.98

9.2.2.2 Non-linear interaction model

Open code
model_GFR_MDRD_MPL_BC_interaction_NL <- run(
  expr = brm_multiple(
    GFR_MDRD ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(I(MPL_BC_log2-2), bs = 'ps', k = 5) +
    s(I(MPL_BC_log2-2), by = infliximab, bs = 'ps', k = 5),
    family = student(),
    data = data_imputed,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 2000, warmup = 1900,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_MPL_BC_interaction_NL",
  reuse = TRUE
)

summary(model_GFR_MDRD_MPL_BC_interaction_NL, robust = TRUE)
## Warning: Parts of the model have not converged (some Rhats are > 1.05). Be
## careful when analysing the results! We recommend running more iterations and/or
## setting stronger priors.
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(I(MPL_BC_log2 - 2), bs = "ps", k = 5) + s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5) 
##    Data: data_imputed (Number of observations: 177) 
##   Draws: 320 chains, each with iter = 2000; warmup = 1900; thin = 1;
##          total post-warmup draws = 32000
## 
## Smoothing Spline Hyperparameters:
##                                  Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sIMPL_BC_log2M2_1)               5.48      5.15     0.24    26.01 1.01
## sds(sIMPL_BC_log2M2infliximab_1)     4.06      3.78     0.20    18.64 1.00
##                                  Bulk_ESS Tail_ESS
## sds(sIMPL_BC_log2M2_1)              22894    18113
## sds(sIMPL_BC_log2M2infliximab_1)    30115    17762
## 
## Regression Coefficients:
##                              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                       55.26      3.96    47.56    63.03 1.01    17517
## male_sex                        -1.78      3.14    -8.01     4.43 1.01    46798
## Irec_ageM50                      0.07      0.14    -0.22     0.35 1.01    46248
## male_sex_donor                   0.55      3.08    -5.55     6.61 1.01    46056
## IKDPIM50                        -0.18      0.08    -0.33    -0.03 1.01    44542
## ICITM15                          0.28      0.22    -0.16     0.70 1.02    12810
## IHLA_MMM5                       -1.02      1.07    -3.13     1.08 1.06     3228
## perfusion_event                 -6.94      3.37   -13.60    -0.32 1.05     3778
## infliximab                       0.02     79.41  -154.70   156.08 1.02    14644
## sIMPL_BC_log2M2_1               -8.42     11.64   -34.46    19.33 1.01    26393
## sIMPL_BC_log2M2:infliximab_1   -16.06     57.67  -130.78    96.21 1.02    14804
## sIMPL_BC_log2M2:infliximab_2    11.92     19.62   -26.46    49.76 1.01    15212
##                              Tail_ESS
## Intercept                       30328
## male_sex                        26548
## Irec_ageM50                     27384
## male_sex_donor                  26969
## IKDPIM50                        28281
## ICITM15                         26355
## IHLA_MMM5                       11257
## perfusion_event                 13872
## infliximab                      19342
## sIMPL_BC_log2M2_1               20425
## sIMPL_BC_log2M2:infliximab_1    19537
## sIMPL_BC_log2M2:infliximab_2    20207
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    18.31      1.22    15.93    20.78 1.01    35683    24148
## nu       19.59     10.89     6.60    56.82 1.00    38348    26532
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_GFR_MDRD_MPL_BC_interaction_NL)
##                         prior     class
##                        (flat)         b
##   normal(0, 5.67833744497037)         b
##   normal(0, 27.9998143727979)         b
##   normal(0, 1.96696986241627)         b
##   normal(0, 81.0302607180105)         b
##   normal(0, 3.86088452959197)         b
##   normal(0, 81.0302607180105)         b
##   normal(0, 81.0302607180105)         b
##   normal(0, 81.0302607180105)         b
##                        (flat)         b
##                        (flat)         b
##                        (flat)         b
##  normal(51.900395480226, 200) Intercept
##                 gamma(2, 0.1)        nu
##           student_t(3, 0, 18)       sds
##           student_t(3, 0, 12)       sds
##            student_t(3, 0, 6)       sds
##           student_t(3, 0, 18)     sigma
##                                                      coef group resp dpar nlpar
##                                                                                
##                                                   ICITM15                      
##                                                 IHLA_MMM5                      
##                                                  IKDPIM50                      
##                                                infliximab                      
##                                               Irec_ageM50                      
##                                                  male_sex                      
##                                            male_sex_donor                      
##                                           perfusion_event                      
##                                         sIMPL_BC_log2M2_1                      
##                              sIMPL_BC_log2M2:infliximab_1                      
##                              sIMPL_BC_log2M2:infliximab_2                      
##                                                                                
##                                                                                
##                                                                                
##                   s(I(MPL_BC_log2 - 2), bs = "ps", k = 5)                      
##  s(I(MPL_BC_log2 - 2), by = infliximab, bs = "ps", k = 5)                      
##                                                                                
##  lb ub       source
##             default
##                user
##                user
##                user
##                user
##                user
##                user
##                user
##                user
##        (vectorized)
##        (vectorized)
##        (vectorized)
##                user
##   1         default
##   0         default
##   0            user
##   0            user
##   0         default


tr2 <- round(fixef(model_GFR_MDRD_MPL_BC_interaction_NL, 
                   robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)

antibody_seq <- quantile(data_model_priorImpute$MPL_BC_log2, probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `MPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_GFR_MDRD_MPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get Estimate for infliximab effect across antibody values
prediction <- (
  prediction_infliximab-
     prediction_ctrl
  ) %>% data.frame()
names(prediction) <- c('p05', 'p95')

infliximab_MPL_BC_log2_int <- quantile((prediction$p95 - prediction$p05)/scaling_unit, 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_MPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:MPL_BC_log2'
kableExtra::kable(tr2)
Table 19: Results from a multivariable Bayesian robust regression model incorporating a non-linear interaction between anti-cardiolipin IgM (MPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR, GFR_MDRD), while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:MPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgM, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
Estimate Q2.5 Q97.5
male_sex -1.78 -8.01 4.43
Irec_ageM50 0.07 -0.22 0.35
male_sex_donor 0.55 -5.55 6.61
IKDPIM50 -0.18 -0.33 -0.03
ICITM15 0.28 -0.16 0.70
IHLA_MMM5 -1.02 -3.13 1.08
perfusion_event -6.94 -13.60 -0.32
infliximab:MPL_BC_log2 -23.76 -43.26 -4.64

9.2.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_model_priorImpute$MPL_BC_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
  male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `MPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_GFR_MDRD_MPL_BC_interaction_NL,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')), 
  MPL_BC_log2 = data_prediction$MPL_BC_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control")), 
         `Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>% 
  ggplot(aes(x = MPL_BC_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 125),
                     breaks = c(seq(0, 125, by = 25))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  geom_point(data = data_model_priorImpute, 
             aes(x = MPL_BC_log2, y = GFR_MDRD, col = group, fill = group)) +
  
  labs(x = expression(log[2]~"(aCL IgM ["*mu*"g/ml])"), y = "GFR (mL/min/1.73 m²)") +
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") +
  
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##        0%      100% 
## -5.532591  5.416829

tr <-  posterior_epred(
    model_GFR_MDRD_MPL_BC_interaction_NL,
    newdata = data_prediction)

tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)]) /
  (antibody_seq[2] - antibody_seq[1])

tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_MPL_BC_log2 = tr_ctrl,
  b_MPL_BC_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = (b_MPL_BC_log2), 
         infliximab = (b_MPL_BC_log2_infliximab)) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##       control infliximab
## 2.5%    -1.84      -5.99
## 97.5%    4.77       0.03
## 50%      1.46      -2.96
## 0.1%    -4.09      -8.08
## 99.9%    6.97       2.08

xpos <- 15

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aCL IgM on GFR (mL/min/1.73 m²) ", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(-20, 20)) +
  
                     
                     
  
  geom_vline(xintercept = 0, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Estimate: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Estimate: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30
xseq <- c(1/64, 1/8, 1, 8, 64, 512)

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
##         5%        25%        50%        75%        95% 
## -0.3963058  1.0933124  2.0432905  2.9421729  4.5810923

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `MPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_GFR_MDRD_MPL_BC_interaction_NL,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  prediction_infliximab-
     prediction_ctrl
  ) %>% data.frame()

names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(1)

CIS
##         p05   p25   p50   p75   p95
## 2.5%   -3.1  -5.8  -9.5 -14.8 -28.6
## 97.5%  18.7   8.2   2.8  -0.5  -3.8
## 50%     7.7   1.1  -3.3  -7.7 -16.0
## 0.1%  -10.1 -10.1 -13.0 -18.9 -35.7
## 99.9%  24.8  12.1   6.4   3.4   3.6

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'MPL_BC_percentile') %>% 
  
  ggplot(aes(y = MPL_BC_percentile, x = value, fill = MPL_BC_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)", 
         y = 'Percentile of aCL IgM value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(-40, 40)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  
  geom_vline(xintercept = 0, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Estimate: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Estimate: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Estimate: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Estimate: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Estimate: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

9.2.3.1 Figure merged

Open code
plotac <- 'sup_figure_5'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 8: Anti-cardiolipin IgM modulates the effect of infliximab on estimated glomerular filtration rate (eGFR). (A) Predicted eGFR by anti-cardiolipin IgM for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regions) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of cardiolipin levels. (B) Posterior distribution of the average effect of doubling anti-cardiolipin IgM on eGFR. (C) Posterior distribution of the effect of infliximab on eGFR across anti-cardiolipin IgM percentiles. Results are from a multivariable Bayesian robust regression with B-splines.

10 Summarizing table

Open code
data_results_table_OR <- data.frame(
  
  outcome = c('DGF', 'DGF', 'infecition', 'infection'),
  
  antibody = c('aCL IgG', 'aCL IgM', 'aPE-dep IgG', 'aPE-ind IgG'),
  
  IFX_OR_p05 = c('0.13 [0.03, 0.49]',
                    '0.23 [0.05, 0.94]',
                    '3.73 [1.15, 12.69]',
                    '3.12 [1.11, 9.08]'
                    ),
  
  IFX_OR_p25 = c('0.34 [0.13, 0.80]',
                    '0.48 [0.19, 1.15]',
                    '2.26 [1.005, 5.19]',
                    '2.34 [1.01, 5.56]'
                    ),
  
  IFX_OR_p50 = c('0.59 [0.27, 1.25]',
                    '0.77 [0.37, 1.61]',
                    '1.68 [0.82, 3.47]',
                    '1.75 [0.85, 3.68]'
                    ),
  
  IFX_OR_p75 = c('1.37 [0.60, 3.22]',
                    '1.22 [0.52, 2.85]',
                    '1.10 [0.49, 2.42]',
                    '1.02 [0.45, 2.26]'
                    ),
  
  IFX_OR_p95 = c('6.24 [1.38, 30.32]',
                    '2.79 [0.66, 12.59]',
                    '0.36 [0.07, 1.75]',
                    '0.23 [0.03, 1.33]'
                    ),
  
    p95_per_p05_ROR = c('46.6 [4.4, 610.0]',
                     '12.8 [1.1, 166.6]',
                     '0.097 [0.008, 0.995]',
                     '0.08 [0.005, 0.75]'
                     )
)

data_results_table_cont <- data.frame(
  
  outcome = c('eGFR', 'eGFR'),
  
  antibody = c('aCL IgG', 'aCL IgM'),
  
  IFX_eff_p05 = c('7.7 [-2.4, 17.9]',
                    '7.7 [-3.1, 18.7]'),
  
  IFX_eff_p25 = c('2.0 [-4.8, 8.8]',
                    '1.1 [-5.8, 8.2]'),
  
  IFX_eff_p50 = c('-1.7 [-7.7, 4.5]',
                    '-3.3 [-9.5, 2.8]'),
  
  IFX_eff_p75 = c('-7.2 [-14.1, -0.3]',
                    '-7.7 [-14.8, -0.5]'),
  
  IFX_eff_p95 = c('-17.4 [-30.0, -5.1]',
                    '-16.0 [-28.6, -3.8]'),
  
  p95_p05_DE = c('-25.2 [-43.7, -6.8]',
                    '-24.8 [-43.2, -4.6]')
)

kableExtra::kable(data_results_table_OR)
kableExtra::kable(data_results_table_cont)
Table 20: Results from multivariable Bayesian logistic (A) and robust (B) regression models with B-splines, estimating the non-linear interaction between natural antibody (antibody) levels and infliximab (IFX) treatment on the specified outcome. The antibody include anti-cardiolipin IgG or IgM (aCL IgG or IgM) and co-factor (ind)dependent anti-phosphatidylethanolamine (aPE-dep IgG and aPE-ind IgG respectively). IFX treatment effects (odds ratio [OR] for logistic models, absolute effect [eff] for robust regression) are reported at the 5th, 25th, 50th, 75th, and 95th percentiles of nAb levels, each with [95% credible interval]. Interaction magnitudes are expressed as the ratio of odds ratios (ROR) for the IFX effect at the 95th vs. 5th percentile of the nAb level (p95_per_p05_ROR) in logistic models (A) and as the difference in treatment effects at the 95th minus 5th percentile (p95_p05_DE) in robust regression (B), both with [95% credible intervals]
outcome antibody IFX_OR_p05 IFX_OR_p25 IFX_OR_p50 IFX_OR_p75 IFX_OR_p95 p95_per_p05_ROR
DGF aCL IgG 0.13 [0.03, 0.49] 0.34 [0.13, 0.80] 0.59 [0.27, 1.25] 1.37 [0.60, 3.22] 6.24 [1.38, 30.32] 46.6 [4.4, 610.0]
DGF aCL IgM 0.23 [0.05, 0.94] 0.48 [0.19, 1.15] 0.77 [0.37, 1.61] 1.22 [0.52, 2.85] 2.79 [0.66, 12.59] 12.8 [1.1, 166.6]
infecition aPE-dep IgG 3.73 [1.15, 12.69] 2.26 [1.005, 5.19] 1.68 [0.82, 3.47] 1.10 [0.49, 2.42] 0.36 [0.07, 1.75] 0.097 [0.008, 0.995]
infection aPE-ind IgG 3.12 [1.11, 9.08] 2.34 [1.01, 5.56] 1.75 [0.85, 3.68] 1.02 [0.45, 2.26] 0.23 [0.03, 1.33] 0.08 [0.005, 0.75]
outcome antibody IFX_eff_p05 IFX_eff_p25 IFX_eff_p50 IFX_eff_p75 IFX_eff_p95 p95_p05_DE
eGFR aCL IgG 7.7 [-2.4, 17.9] 2.0 [-4.8, 8.8] -1.7 [-7.7, 4.5] -7.2 [-14.1, -0.3] -17.4 [-30.0, -5.1] -25.2 [-43.7, -6.8]
eGFR aCL IgM 7.7 [-3.1, 18.7] 1.1 [-5.8, 8.2] -3.3 [-9.5, 2.8] -7.7 [-14.8, -0.5] -16.0 [-28.6, -3.8] -24.8 [-43.2, -4.6]

11 GFR: Mediation and AB-subgroup analysis

11.1 GPL_BC subgroup, DGF mediation

11.1.1 Define the subgroups

Open code
GPL_median <- median(data_model_priorImpute$GPL_BC_log2)
GPL_median
## [1] -0.1046076


data_imputed_highGPL <- data.frame(subset(
  data_first, 
  subset = data_first$GPL_BC_log2 >= GPL_median
))


data_imputed_lowGPL <- subset(
  data_first, 
  subset = data_first$GPL_BC_log2 < GPL_median
)

11.1.2 Priors

Open code
create_prior <- function(var, sigma, class = "b") {
  set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = var)
}

GFR_sd <- sd(data_model_priorImpute$GFR_MDRD)
GFR_sd
## [1] 20.25757

priors_subset <- c(
  
  create_prior("Irec_ageM50",
    (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE)
  ),
  create_prior("IHLA_MMM5",
    (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE)
  ),
  create_prior("IKDPIM50",
    (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE)
  ),
  create_prior("ICITM15",
    (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE)
  ),
  create_prior("male_sex",
    4*GFR_sd
  ),
  create_prior("perfusion_event",
    4*GFR_sd
  ),
  create_prior("male_sex_donor",
    4*GFR_sd
  ),
  create_prior("infliximab",
    4*GFR_sd
  ),

  set_prior(paste0("normal(", mean(data_model_priorImpute$GFR_MDRD), ", 200)"),
    class = "Intercept"
  )
)


create_prior <- function(var, sigma, class = "b",  resp = 'GFR_MDRD') {
  set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = var, resp = resp)
}

priors_mediation <- c(
  
  create_prior("Irec_ageM50",
    (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE)
  ),
  
  create_prior("Irec_ageM50",
    (2*GFR_sd) / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    resp = 'DGF'
  ),
  
  create_prior("IHLA_MMM5",
    (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE)
  ),
  create_prior("IHLA_MMM5",
    (2*GFR_sd) / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    resp = 'DGF'
  ),
  
  
  create_prior("IKDPIM50",
    (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE)
  ),
  create_prior("IKDPIM50",
    (2*GFR_sd) / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    resp = 'DGF'
  ),
  
  create_prior("ICITM15",
    (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE)
  ),
  create_prior("ICITM15",
    (2*GFR_sd) / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    resp = 'DGF'
  ),
  
  
  create_prior("male_sex",
    4*GFR_sd
  ),
  create_prior("male_sex",
    4*GFR_sd,
    resp = 'DGF'
  ),
  
  
  create_prior("perfusion_event",
    4*GFR_sd
  ),
  create_prior("perfusion_event",
    4*GFR_sd,
    resp = 'DGF'
  ),
  
  create_prior("male_sex_donor",
    4*GFR_sd
  ),
  create_prior("male_sex_donor",
    4*GFR_sd,
    resp = 'DGF'
  ),
  
  create_prior("infliximab",
    4*GFR_sd
  ),
  create_prior("infliximab",
    4*GFR_sd,
    resp = 'DGF'
  ),
  
  
  create_prior("DGF",
    4*GFR_sd
  )
)

11.1.3 GPL subgroup models

Open code
model_GFR_MDRD_GPLsubset_low <- run(
  expr = brm(
    GFR_MDRD ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event + 
     # GPL_BC_log2 +
      infliximab,
    family = student(),
    data = data_imputed_lowGPL,
    prior = priors_subset,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 6000, warmup = 2000,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_GPLsubset_low",
  reuse = TRUE
)

summary(model_GFR_MDRD_GPLsubset_low)
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab 
##    Data: data_imputed_lowGPL (Number of observations: 88) 
##   Draws: 4 chains, each with iter = 6000; warmup = 2000; thin = 1;
##          total post-warmup draws = 16000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          53.64      6.14    41.70    65.79 1.00    12937    12099
## male_sex           -4.62      4.63   -13.77     4.51 1.00    15868    12555
## Irec_ageM50         0.11      0.22    -0.32     0.54 1.00    15296    12996
## male_sex_donor     -1.07      4.42    -9.76     7.58 1.00    16194    12207
## IKDPIM50           -0.07      0.12    -0.30     0.16 1.00    13512    12251
## ICITM15             0.27      0.34    -0.39     0.93 1.00    15680    11690
## IHLA_MMM5          -2.69      1.56    -5.71     0.42 1.00    14006    11874
## perfusion_event   -10.42      4.51   -19.28    -1.59 1.00    15569    11275
## infliximab          7.95      4.34    -0.56    16.52 1.00    15538    12635
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    18.38      1.72    15.18    21.98 1.00    13123    10365
## nu       21.59     13.33     5.59    55.41 1.00    12924    10419
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

model_GFR_MDRD_GPLsubset_high <- run(
  expr = brm(
    GFR_MDRD ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      #GPL_BC_log2 +
      infliximab,
    family = student(),
    data = data_imputed_highGPL,
    prior = priors_subset,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 6000, warmup = 2000,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_GPLsubset_high",
  reuse = TRUE
)

summary(model_GFR_MDRD_GPLsubset_high)
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab 
##    Data: data_imputed_highGPL (Number of observations: 89) 
##   Draws: 4 chains, each with iter = 6000; warmup = 2000; thin = 1;
##          total post-warmup draws = 16000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          57.76      4.73    48.55    67.15 1.00    16997    12841
## male_sex           -0.24      4.23    -8.56     8.08 1.00    15905    12133
## Irec_ageM50        -0.04      0.19    -0.43     0.34 1.00    16471    12080
## male_sex_donor      1.38      4.40    -7.30    10.07 1.00    15460    12845
## IKDPIM50           -0.30      0.11    -0.51    -0.10 1.00    14493    12398
## ICITM15             0.20      0.28    -0.36     0.75 1.00    15661    12193
## IHLA_MMM5          -0.52      1.45    -3.37     2.30 1.00    15902    12189
## perfusion_event    -1.74      4.57   -10.80     7.29 1.00    13721    11816
## infliximab        -13.28      4.16   -21.38    -5.08 1.00    15993    12761
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    17.66      1.67    14.50    21.12 1.00    12364     9869
## nu       22.05     13.62     5.26    56.17 1.00    12209    10212
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

11.1.4 Mediation

Prepare table

Open code
# Model for the mediator DGF
m1 <- bf(
  DGF ~ scale(male_sex) +
    scale(rec_age) +
    scale(male_sex_donor) +
    scale(KDPI) +
    scale(CIT) +
    scale(HLA_MM) +
    scale(perfusion_event) +
    infliximab,
  family = bernoulli(link = "logit")
)


# Model for the outcome GFR
m2 <- bf(
  GFR_MDRD ~ scale(male_sex) +
    scale(rec_age) +
    scale(male_sex_donor) +
    scale(KDPI) +
    scale(CIT) +
    scale(HLA_MM) +
    scale(perfusion_event) +
    infliximab +
    DGF,
  family = student()
)

## Joint model - Low GPL_BC
model_GFR_GPL_mediate_low <- run(
  expr = brm(
  m1 + m2 + set_rescor(FALSE),
  data = data_imputed_lowGPL,
  priors_mediation,
  backend = "cmdstanr",
  seed = 2025,
  cores = 4, chains = 4,
  iter = 6000, warmup = 2000,
  control = list(adapt_delta = 0.95), refresh = 0),
  path = "gitignore/run/model_GFR_GPL_mediate_low",
  reuse = TRUE
)


## Joint model - high GPL_BC
model_GFR_GPL_mediate_high <- run(
  expr = brm(
  m1 + m2 + set_rescor(FALSE),
  data = data_imputed_highGPL,
  priors_mediation,
  backend = "cmdstanr",
  seed = 2025,
  cores = 4, chains = 4,
  iter = 6000, warmup = 2000,
  control = list(adapt_delta = 0.95), refresh = 0),
  path = "gitignore/run/model_GFR_GPL_mediate_high",
  reuse = TRUE
)



post_fix_low <- as.data.frame(model_GFR_GPL_mediate_low) %>% 
  
  select(b_GFRMDRD_Intercept, b_GFRMDRD_infliximab, b_GFRMDRD_DGF,
         b_DGF_Intercept, b_DGF_infliximab) %>% 
  
  mutate(predicted_DGF_ctrl = inv_logit(b_DGF_Intercept),
         predicted_DGF_infx = inv_logit(b_DGF_Intercept + b_DGF_infliximab)) %>% 
  
  mutate(
    indirect_pred_ctrl = b_GFRMDRD_Intercept + 
      (b_GFRMDRD_infliximab * mean(data_imputed_lowGPL$infliximab) ) +
      (b_GFRMDRD_DGF * predicted_DGF_ctrl),
    
    indirect_pred_infx = b_GFRMDRD_Intercept + 
      (b_GFRMDRD_infliximab * mean(data_imputed_lowGPL$infliximab) ) +
      (b_GFRMDRD_DGF * predicted_DGF_infx),
      ) %>% 
  
  mutate(
    `Direct Effect (ADE)`  = b_GFRMDRD_infliximab,
    `Indirect Effect (ACME)` = indirect_pred_infx - indirect_pred_ctrl,
    `Mediator Effect` = b_GFRMDRD_DGF,
    `Total Effect` = (
           (indirect_pred_infx - indirect_pred_ctrl) + b_GFRMDRD_infliximab
           )
         ) %>% 
  select(`Direct Effect (ADE)`:`Total Effect`)

med_eff_low <- sapply(
  post_fix_low,
  function(p) quantile(p, probs = c(0.5, 0.025, 0.975))
  ) %>% t() 


post_fix_high <- as.data.frame(model_GFR_GPL_mediate_high) %>% 
  
  select(b_GFRMDRD_Intercept, b_GFRMDRD_infliximab, b_GFRMDRD_DGF,
         b_DGF_Intercept, b_DGF_infliximab) %>% 
  
  mutate(predicted_DGF_ctrl = inv_logit(b_DGF_Intercept),
         predicted_DGF_infx = inv_logit(b_DGF_Intercept + b_DGF_infliximab)) %>% 
  
  mutate(
    indirect_pred_ctrl = b_GFRMDRD_Intercept + 
      (b_GFRMDRD_infliximab * mean(data_imputed_highGPL$infliximab) ) +
      (b_GFRMDRD_DGF * predicted_DGF_ctrl),
    
    indirect_pred_infx = b_GFRMDRD_Intercept + 
      (b_GFRMDRD_infliximab * mean(data_imputed_highGPL$infliximab) ) +
      (b_GFRMDRD_DGF * predicted_DGF_infx),
      ) %>% 
  
  mutate(
    `Direct Effect (ADE)`  = b_GFRMDRD_infliximab,
    `Indirect Effect (ACME)` = indirect_pred_infx - indirect_pred_ctrl,
    `Mediator Effect` = b_GFRMDRD_DGF,
    `Total Effect` = (
           (indirect_pred_infx - indirect_pred_ctrl) + b_GFRMDRD_infliximab
           )
         ) %>% 
  select(`Direct Effect (ADE)`:`Total Effect`)


med_eff_high <- sapply(
  post_fix_high,
  function(p) quantile(p, probs = c(0.5, 0.025, 0.975))
  ) %>% t()


mediation_effect <- data.frame(
  effect = rownames(med_eff_low),
  `Low_aCL` = paste0(
    round(c(med_eff_low[, 1]), 1), 
    ' [', 
    round(c(med_eff_low[, 2]), 1), 
    ', ', 
    round(c(med_eff_low[, 3]), 1),
    ']'
    ),
  `High_aCL` = paste0(
    round(c(med_eff_high[, 1]), 1), 
    ' [', 
    round(c(med_eff_high[, 2]), 1), 
    ', ', 
    round(c(med_eff_high[, 3]), 1),
    ']'
    )
  )

Print table

Open code
kableExtra::kable(mediation_effect)
Table 21: Results from Bayesian mediation analyses assessing the direct and indirect effects of infliximab on estimated glomerular filtration rate (eGFR). The indirect effect operates through the impact of infliximab on delayed graft function (DGF) risk. Separate joint models were used for patients with anti-cardiolipin IgG (aCL IgG) below (Low aCL) and at/above the median (High aCL). The Average Direct Effect (ADE [95% credible interval]) estimates the direct effect of infliximab on eGFR, controlling for the indirect pathway via DGF and other covariates. The Average Causal Mediation Effect (ACME [95% credible interval]) quantifies the indirect effect via DGF. The Mediator Effect represents the effect of DGF on eGFR, adjusting for infliximab and other covariates. The Total Effect captures the overall impact of infliximab on eGFR, combining both direct and indirect pathways.
effect Low_aCL High_aCL
Direct Effect (ADE) 2.1 [-6.1, 10.1] -11.1 [-19.1, -2.9]
Indirect Effect (ACME) 5.4 [1.6, 10.6] -2.3 [-6.6, 0.3]
Mediator Effect -18.5 [-27, -9.9] -12.3 [-20.9, -3.7]
Total Effect 7.7 [-1, 16.1] -13.6 [-22.1, -5.1]

12 Models without large GPL_BC

Open code

infl_max <- max(data_first[which(data_first$infliximab == 1), 'GPL_BC_log2']); infl_max
## [1] 2.740331
ctrl_max <- max(data_first[which(data_first$infliximab == 0), 'GPL_BC_log2']); ctrl_max
## [1] 4.949819

data_sens <- data_first %>% filter(GPL_BC_log2 <= infl_max) %>% 
  mutate(group = factor(if_else(infliximab == 1, 'infliximab', 'control')))

12.1 DGF by GPL_BC

12.1.1 Priors

Open code

# function to get prior
create_prior <- function(var, sigma, class = "b", coef = NULL) {
  set_prior(paste0("normal(0, ", sigma, ")"), class = class, coef = coef)
}


priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               2 / sd(data_sens$rec_age, na.rm = TRUE),
               coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               2 / sd(data_sens$HLA_MM, na.rm = TRUE),
               coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               2 / sd(data_sens$KDPI, na.rm = TRUE),
               coef = "IKDPIM50"),
  create_prior("ICITM15",
               2 / sd(data_sens$CIT, na.rm = TRUE),
               coef = "ICITM15"),
  create_prior("male_sex",
               4,
               coef = "male_sex"),
  create_prior("perfusion_event",
               4,
               coef = "perfusion_event"),
  create_prior("male_sex_donor",
               4,
               coef = "male_sex_donor"),

  create_prior("infliximab",
               4,
               coef = "infliximab"),

 set_prior("student_t(3, 0, 0.6)", class = "sds", 
           coef = 's(GPL_BC_log2, bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 0.3)", class = "sds",  
           coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", logit(mean(data_sens$DGF)), ", 10)"),
            class = "Intercept")
)

12.1.2 Model

Open code
model_dgf_GPL_BC_interaction_NL_sens <- run(
  expr = brm(
    DGF ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(GPL_BC_log2, bs = 'ps', k = 5) +
    s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
    family = bernoulli(),
    data = data_sens,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 5000, warmup = 2000,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_GPL_BC_interaction_NL_sens",
  reuse = TRUE
)

summary(model_dgf_GPL_BC_interaction_NL_sens, robust = TRUE)
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 
##    Data: data_sens (Number of observations: 170) 
##   Draws: 4 chains, each with iter = 5000; warmup = 2000; thin = 1;
##          total post-warmup draws = 12000
## 
## Smoothing Spline Hyperparameters:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1)               0.45      0.40     0.02     1.88 1.00
## sds(sGPL_BC_log2infliximab_1)     0.22      0.21     0.01     1.07 1.00
##                               Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1)               7041     5216
## sds(sGPL_BC_log2infliximab_1)     8954     5147
## 
## Regression Coefficients:
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                    -1.23      0.49    -2.25    -0.26 1.00    11736
## male_sex                      1.15      0.41     0.35     1.99 1.00    12193
## Irec_ageM50                  -0.01      0.02    -0.05     0.03 1.00    11702
## male_sex_donor                0.31      0.40    -0.45     1.11 1.00    10843
## IKDPIM50                      0.00      0.01    -0.02     0.02 1.00    10691
## ICITM15                       0.09      0.03     0.03     0.15 1.00    10923
## IHLA_MMM5                     0.25      0.14    -0.01     0.52 1.00    10410
## perfusion_event              -0.39      0.39    -1.17     0.39 1.00    11052
## infliximab                    0.06      3.89    -7.58     7.58 1.00     3997
## sGPL_BC_log2_1                2.05      1.19    -0.39     4.66 1.00     7724
## sGPL_BC_log2:infliximab_1     1.65      2.73    -3.57     6.90 1.00     4254
## sGPL_BC_log2:infliximab_2    -2.09      1.33    -4.69     0.48 1.00     4694
##                           Tail_ESS
## Intercept                     9635
## male_sex                      9580
## Irec_ageM50                   9522
## male_sex_donor                8929
## IKDPIM50                      8477
## ICITM15                       8949
## IHLA_MMM5                     8917
## perfusion_event               9013
## infliximab                    5974
## sGPL_BC_log2_1                6425
## sGPL_BC_log2:infliximab_1     6490
## sGPL_BC_log2:infliximab_2     6814
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_GPL_BC_interaction_NL_sens)
##                           prior     class
##                          (flat)         b
##    normal(0, 0.281193624307594)         b
##     normal(0, 1.32489040521642)         b
##   normal(0, 0.0974514024084987)         b
##                    normal(0, 4)         b
##    normal(0, 0.194443540354437)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                    normal(0, 4)         b
##                          (flat)         b
##                          (flat)         b
##                          (flat)         b
##  normal(-0.658055860748675, 10) Intercept
##            student_t(3, 0, 2.5)       sds
##            student_t(3, 0, 0.6)       sds
##            student_t(3, 0, 0.3)       sds
##                                               coef group resp dpar nlpar lb ub
##                                                                               
##                                            ICITM15                            
##                                          IHLA_MMM5                            
##                                           IKDPIM50                            
##                                         infliximab                            
##                                        Irec_ageM50                            
##                                           male_sex                            
##                                     male_sex_donor                            
##                                    perfusion_event                            
##                                     sGPL_BC_log2_1                            
##                          sGPL_BC_log2:infliximab_1                            
##                          sGPL_BC_log2:infliximab_2                            
##                                                                               
##                                                                           0   
##                   s(GPL_BC_log2, bs = "ps", k = 5)                        0   
##  s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)                        0   
##        source
##       default
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##  (vectorized)
##  (vectorized)
##  (vectorized)
##          user
##       default
##          user
##          user

tr2 <- round(exp(fixef(model_dgf_GPL_BC_interaction_NL_sens, 
                       robust = TRUE)[-c(1,9:12), c(1,3,4)]), 2)

antibody_seq <- quantile(data_sens$GPL_BC_log2, 
                         probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_dgf_GPL_BC_interaction_NL_sens,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get odds ratio for infliximab effect across antibody values
prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()
names(prediction) <- c('p05', 'p95')

infliximab_GPL_BC_log2_int <- quantile(
  exp((log(prediction$p95) - log(prediction$p05))/scaling_unit), 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
colnames(tr2)[1] <- '(R)OR'
kableExtra::kable(tr2)
Table 22: Results from multivariable Bayesian logistic regression models incorporating a non-linear interaction between anti-cardiolipin IgG (GPL_BC_log2) and infliximab treatment on delayed graft function (DGF), while accounting for other covariates, restricting the dataset to patients with anti-cardiolipin IgG levels within the range observed in the infliximab group. Effects are presented as odds ratios (OR), with the last row reporting the ratio of odds ratios (ROR). The ROR represents the estimated ratio of infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect.Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
(R)OR Q2.5 Q97.5
male_sex 3.16 1.43 7.31
Irec_ageM50 0.99 0.95 1.03
male_sex_donor 1.36 0.64 3.04
IKDPIM50 1.00 0.98 1.02
ICITM15 1.09 1.03 1.16
IHLA_MMM5 1.28 0.99 1.68
perfusion_event 0.68 0.31 1.47
infliximab:GPL_BC_log2 49.76 4.11 715.86

12.1.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_sens$GPL_BC_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_dgf_GPL_BC_interaction_NL_sens,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')), 
  GPL_BC_log2 = data_prediction$GPL_BC_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control"))) %>% 
  ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 1),
                     breaks = c(seq(0, 1, by = 0.2))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"), y = "DGF risk") +
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size=10),
        axis.title=element_text(size=12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") +
  
  geom_rug(
    data = data_sens %>% filter(DGF == 0),
    aes(x = GPL_BC_log2),
    sides = "b",
    color = "black",
    size = 0.12,
    inherit.aes = FALSE
  ) +
  geom_rug(
    data = data_sens %>% filter(DGF == 1),
    aes(x = GPL_BC_log2),
     sides = "t",
    color = "black",
    linewidth = 0.12,
    inherit.aes = FALSE
  ) + 
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##        0%      100% 
## -3.861561  2.740331

tr <-  posterior_epred(
    model_dgf_GPL_BC_interaction_NL_sens,
    newdata = data_prediction)

tr_ctrl <- (logit(tr[,c(ncol(tr)/2)]) - logit(tr[,c(1)])) /
  (antibody_seq[2] - antibody_seq[1])
tr_infliximab <- (logit(tr[,c(ncol(tr))]) - logit(tr[,c(ncol(tr)/2)+1]))/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_GPL_BC_log2 = tr_ctrl,
  b_GPL_BC_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = exp(b_GPL_BC_log2), 
         infliximab = exp(b_GPL_BC_log2_infliximab)) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(1)

CIS
##       control infliximab
## 2.5%      0.4        1.0
## 97.5%     1.0        2.8
## 50%       0.6        1.7
## 0.1%      0.3        0.7
## 99.9%     1.3        4.0

xpos <- 10

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aCL IgG on DGF risk (OR))", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(1/20, 20)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(1/16, 1/4, 1, 4 ,16),
                     labels = c("1/16", "1/4", "1", "4", "16")) +
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 240
xseq <- c(1/64, 1/8, 1, 8, 64, 512)

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]
antibody_seq
##         5%        25%        50%        75%        95% 
## -1.8017117 -0.7949708 -0.1340217  0.6308746  2.0711263

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_dgf_GPL_BC_interaction_NL_sens,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  (prediction_infliximab/(1-prediction_infliximab))/
     (prediction_ctrl/(1-prediction_ctrl))
  ) %>% data.frame()


names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##        p05  p25  p50  p75   p95
## 2.5%  0.02 0.11 0.26 0.54  1.21
## 97.5% 0.46 0.74 1.23 2.93 27.34
## 50%   0.11 0.30 0.58 1.26  5.61
## 0.1%  0.01 0.06 0.16 0.33  0.50
## 99.9% 1.08 1.29 1.89 4.75 66.13

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'GPL_BC_percentile') %>% 
  
  ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on DGF risk (odds ratio)", 
         y = 'Percentile of aCL IgG value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(1/300, 1150)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  scale_x_continuous(transform = 'log2',
                     breaks = c(xseq),
                     labels = c("1/64", "1/8", "1", "8", "64", '512')) +
  
  
  geom_vline(xintercept = 1, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Odds ratio: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Odds ratio: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Odds ratio: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Odds ratio: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Odds ratio: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

12.1.3.1 Figure merged

Open code


plotac <- "sup_figure_2"
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 9: Anti-cardiolipin IgG modulation of the effect of infliximab on delayed graft function (DGF) after excluding patients with anti-cardiolipin IgG levels above the maximum in the IFX group. (A) Predicted DGF risk by anti-cardiolipin IgG for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regions) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles. (B) Posterior distribution of the average effect (odds ratio) of doubling anti-cardiolipin IgG on DGF risk. (C) Posterior distribution of the effect of infliximab (odds ratio) on DGF across anti-cardiolipin IgG percentiles. Results are from a multivariable Bayesian logistic model with B-splines after data restriction.

12.2 GFR by GPL_BC

12.2.1 Prior

Open code
priors_interaction_pnl <- c(
  create_prior("Irec_ageM50",
               (2*GFR_sd) / sd(data_sens$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"),  
  create_prior("IHLA_MMM5",
               (2*GFR_sd) / sd(data_sens$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"),
  create_prior("IKDPIM50",
               (2*GFR_sd) / sd(data_sens$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"),
  create_prior("ICITM15",
               (2*GFR_sd) / sd(data_sens$CIT, na.rm = TRUE),
    coef = "ICITM15"),
  create_prior("male_sex",
    4*GFR_sd,
    coef = "male_sex"),
  create_prior("perfusion_event",
    4*GFR_sd,
    coef = "perfusion_event"),
  create_prior("male_sex_donor",
    4*GFR_sd,
    coef = "male_sex_donor"),
  
  create_prior("infliximab",
    4*GFR_sd,
    coef = "infliximab"),

 set_prior("student_t(3, 0, 12)", class = "sds", 
           coef = 's(GPL_BC_log2, bs = "ps", k = 5)'), 
 
 set_prior("student_t(3, 0, 6)", class = "sds",  
           coef = 's(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)'), 
 
  set_prior(paste0("normal(", mean(data_sens$GFR_MDRD), ", 200)"),
            class = "Intercept")
)

12.2.2 Model

Open code
model_GFR_MDRD_GPL_BC_interaction_NL_sens <- run(
  expr = brm(
    GFR_MDRD ~
    male_sex +
    I(rec_age - 50) +
    male_sex_donor +
    I(KDPI - 50) +
    I(CIT - 15) +
    I(HLA_MM - 5) +
    perfusion_event +
    infliximab +
    s(GPL_BC_log2, bs = 'ps', k = 5) +
    s(GPL_BC_log2, by = infliximab, bs = 'ps', k = 5),
    family = student(),
    data = data_sens,
    prior = priors_interaction_pnl,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 5000, warmup = 2000,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_GFR_MDRD_GPL_BC_interaction_NL_sens",
  reuse = TRUE
)

summary(model_GFR_MDRD_GPL_BC_interaction_NL_sens, robust = TRUE)
##  Family: student 
##   Links: mu = identity; sigma = identity; nu = identity 
## Formula: GFR_MDRD ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + s(GPL_BC_log2, bs = "ps", k = 5) + s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5) 
##    Data: data_sens (Number of observations: 170) 
##   Draws: 4 chains, each with iter = 5000; warmup = 2000; thin = 1;
##          total post-warmup draws = 12000
## 
## Smoothing Spline Hyperparameters:
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## sds(sGPL_BC_log2_1)              10.75      6.61     1.51    34.13 1.00
## sds(sGPL_BC_log2infliximab_1)     3.91      3.54     0.16    18.11 1.00
##                               Bulk_ESS Tail_ESS
## sds(sGPL_BC_log2_1)               5999     4257
## sds(sGPL_BC_log2infliximab_1)    10958     5581
## 
## Regression Coefficients:
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                    56.12      3.74    48.82    63.48 1.00    14100
## male_sex                     -3.07      3.18    -9.31     3.20 1.00    17270
## Irec_ageM50                   0.04      0.15    -0.25     0.34 1.00    16383
## male_sex_donor               -1.29      3.09    -7.32     4.89 1.00    15270
## IKDPIM50                     -0.18      0.08    -0.34    -0.02 1.00    14260
## ICITM15                       0.28      0.21    -0.14     0.69 1.00    17187
## IHLA_MMM5                    -1.51      1.04    -3.57     0.57 1.00    14539
## perfusion_event              -5.95      3.21   -12.23     0.30 1.00    17005
## infliximab                    0.77     77.45  -153.15   155.03 1.00     4930
## sGPL_BC_log2_1              -15.85     13.41   -47.71    15.01 1.00     9497
## sGPL_BC_log2:infliximab_1    -9.84     53.57  -113.60    95.89 1.00     5056
## sGPL_BC_log2:infliximab_2     8.10     22.49   -36.47    52.92 1.00     4949
##                           Tail_ESS
## Intercept                    10099
## male_sex                      8274
## Irec_ageM50                   9260
## male_sex_donor                8994
## IKDPIM50                      9179
## ICITM15                       8812
## IHLA_MMM5                     9027
## perfusion_event               9245
## infliximab                    6673
## sGPL_BC_log2_1                7594
## sGPL_BC_log2:infliximab_1     7007
## sGPL_BC_log2:infliximab_2     6600
## 
## Further Distributional Parameters:
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sigma    17.96      1.19    15.64    20.35 1.00    12286     8340
## nu       20.08     10.94     6.86    57.49 1.00    13817     8404
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_GFR_MDRD_GPL_BC_interaction_NL_sens)
##                          prior     class
##                         (flat)         b
##    normal(0, 5.69629817247165)         b
##    normal(0, 26.8390537393692)         b
##     normal(0, 1.9741281361241)         b
##    normal(0, 81.0302607180105)         b
##    normal(0, 3.93895269246326)         b
##    normal(0, 81.0302607180105)         b
##    normal(0, 81.0302607180105)         b
##    normal(0, 81.0302607180105)         b
##                         (flat)         b
##                         (flat)         b
##                         (flat)         b
##  normal(51.1962352941176, 200) Intercept
##                  gamma(2, 0.1)        nu
##          student_t(3, 0, 18.1)       sds
##            student_t(3, 0, 12)       sds
##             student_t(3, 0, 6)       sds
##          student_t(3, 0, 18.1)     sigma
##                                               coef group resp dpar nlpar lb ub
##                                                                               
##                                            ICITM15                            
##                                          IHLA_MMM5                            
##                                           IKDPIM50                            
##                                         infliximab                            
##                                        Irec_ageM50                            
##                                           male_sex                            
##                                     male_sex_donor                            
##                                    perfusion_event                            
##                                     sGPL_BC_log2_1                            
##                          sGPL_BC_log2:infliximab_1                            
##                          sGPL_BC_log2:infliximab_2                            
##                                                                               
##                                                                           1   
##                                                                           0   
##                   s(GPL_BC_log2, bs = "ps", k = 5)                        0   
##  s(GPL_BC_log2, by = infliximab, bs = "ps", k = 5)                        0   
##                                                                           0   
##        source
##       default
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##          user
##  (vectorized)
##  (vectorized)
##  (vectorized)
##          user
##       default
##       default
##          user
##          user
##       default

tr2 <- round(fixef(model_GFR_MDRD_GPL_BC_interaction_NL_sens, 
                       robust = TRUE)[-c(1,9:12), c(1,3,4)], 2)

antibody_seq <- quantile(data_sens$GPL_BC_log2, 
                         probs = c(0.05, 0.95))

asl <- length(antibody_seq)
quant_dif <- antibody_seq[2] - antibody_seq[1]

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL_sens,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]
prediction_infliximab <- tr[, c((asl+1):(asl*2))]

## get Estimate for infliximab effect across antibody values
prediction <- (
  prediction_infliximab-
     prediction_ctrl
  ) %>% data.frame()

names(prediction) <- c('p05', 'p95')

infliximab_GPL_BC_log2_int <- quantile(
  (prediction$p95 - prediction$p05)/scaling_unit, 
         probs = c(0.5, 1/40, 39/40))

tr2 <- rbind(tr2, round(infliximab_GPL_BC_log2_int, 2))
row.names(tr2)[8] <- 'infliximab:GPL_BC_log2'
kableExtra::kable(tr2)
Table 23: Results from a multivariable Bayesian robust regression model incorporating a non-linear interaction between anti-cardiolipin IgG (GPL_BC_log2) and infliximab treatment on estimated glomerular filtration rate (eGFR, GFR_MDRD), after excluding patients with anti-cardiolipin IgG levels above the maximum in the IFX group and while accounting for other covariates. Estimate represents the estimated change in eGFR per one-unit increase in the predictor. The last row (infliximab:GPL_BC_log2) reports the difference in infliximab’s treatment effect at the 95th versus the 5th percentile of anti-cardiolipin IgG, quantifying the interaction effect. Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
Estimate Q2.5 Q97.5
male_sex -3.07 -9.31 3.20
Irec_ageM50 0.04 -0.25 0.34
male_sex_donor -1.29 -7.32 4.89
IKDPIM50 -0.18 -0.34 -0.02
ICITM15 0.28 -0.14 0.69
IHLA_MMM5 -1.51 -3.57 0.57
perfusion_event -5.95 -12.23 0.30
infliximab:GPL_BC_log2 -18.27 -36.99 0.59

12.2.3 Visualisation - penalized non-linear effect

Extract posterior draws

Open code
antibody_perc <- quantile(data_sens$GPL_BC_log2,
                           probs = c(0, 0.02, 0.05, 0.25, 0.5, 0.75, 0.95, 0.98, 1))

antibody_seq <- seq(antibody_perc[1], 
                      antibody_perc[length(antibody_perc)], 
                      length.out = 101)

## create prediction
data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

prediction <- data.frame(
  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL_sens,
    newdata = data_prediction) %>% posterior_summary(
      robust = TRUE
      ) %>% data.frame() %>% select(-Est.Error),
  group = factor(if_else(data_prediction$infliximab == 1, 'infliximab', 'control')),
  GPL_BC_log2 = data_prediction$GPL_BC_log2)

Figure A

Open code
cole <- c('#CD7006', '#0028F0')

fig_a <- prediction %>% 
  mutate(group = factor(group, levels = c("infliximab", "control")), 
         `Q2.5` = if_else(`Q2.5` < 0, 0, `Q2.5`)) %>% 
  ggplot(aes(x = GPL_BC_log2, y = Estimate, col = group, fill = group)) + 
  geom_line(aes(y = Estimate), linewidth = 1) + 
  scale_y_continuous(limits = c(0, 125),
                      breaks = c(seq(0, 125, by = 25))) +
  
  geom_ribbon(aes(ymin = `Q2.5`, ymax = `Q97.5`),
               alpha = 0.4,  color = NA) +
  
  geom_point(data = data_sens, 
             aes(x = GPL_BC_log2, y = GFR_MDRD, col = group, fill = group)) +
  
  labs(x = expression(log[2]~"(aCL IgG ["*mu*"g/ml])"), 
       y = "GFR (mL/min/1.73 m²)") +
  
  scale_color_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_fill_manual(values = cole, 
                       name = "group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  facet_grid(rows = vars(group)) +
  
  theme(axis.text=element_text(size = 10),
        axis.title=element_text(size = 12),
        strip.text.x = element_text(size = 12),
        legend.position = "none") + 
  
  geom_vline(xintercept = antibody_perc[3:7], linetype = 2, 
                            color = "grey50", size = 0.3)

Figure B

Open code

antibody_seq <- antibody_perc[c(1, 9)]
antibody_seq
##        0%      100% 
## -3.861561  2.740331

tr <-  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL_sens,
    newdata = data_prediction)

tr_ctrl <- (tr[,c(ncol(tr)/2)] - tr[,c(1)]) /
  (antibody_seq[2] - antibody_seq[1])
tr_infliximab <- (tr[,c(ncol(tr))] - tr[,c(ncol(tr)/2)+1])/
  (antibody_seq[2] - antibody_seq[1])

post_fix <- data.frame(
  b_GPL_BC_log2 = tr_ctrl,
  b_GPL_BC_log2_infliximab = tr_infliximab
)

tr <- post_fix %>% 
  mutate(control = b_GPL_BC_log2, 
         infliximab = b_GPL_BC_log2_infliximab) %>% 
  select(control, infliximab) %>% 
  data.frame()

CIS <- sapply(
  tr, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(2)

CIS
##       control infliximab
## 2.5%    -0.21      -5.28
## 97.5%    7.41       3.26
## 50%      3.55      -1.13
## 0.1%    -2.41      -7.46
## 99.9%    9.61       6.03

xpos <- 20

fig_b <- tr %>% 
  pivot_longer(values_to = 'value', 
               cols = c('control', 'infliximab'),
               names_to = 'group') %>% 
  ggplot(aes(x = value, y = group, fill = group)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha=0.5,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
    labs(x = "Effect of doubling aCL IgG on GFR (mL/min/1.73 m²) ", 
         y = 'Treatment group') +
  
  scale_fill_manual(values = cole, 
                       name = "Treatment group",
                       breaks = c('control', 'infliximab'),
                       labels = c('control', 'infliximab')) +
  
  scale_y_discrete(expand = expansion(add = 0.1)) +
  coord_cartesian(xlim = c(-20, 26)) +
  
  geom_vline(xintercept = 0, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
   
  annotate("text",  x = xpos, y = 2.85 , 
           label = paste0("Estimate: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85 , 
           label = paste0("Estimate: ", CIS[3,1]),
           color = cole[1] ) +
  
  annotate("text",  x = xpos, y = 2.6 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.6 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

Figure C

Open code

cole <- c("#8B4789", "#8B5F77", "#8B7765", "#6F815C", "#548B54")
xpos <- 30

antibody_seq <- antibody_perc[c(3, 4, 5, 6, 7)]

asl <- length(antibody_seq)

data_prediction <- data.frame(
    male_sex = rep(mmale_sex, 2*length(antibody_seq)),
  `male_sex_donor` = rep(mmale_sex_donor, 2*length(antibody_seq)),
  `perfusion_event` = rep(mperfusion_event, 2*length(antibody_seq)),
  `infliximab` = c(rep(0, length(antibody_seq)), rep(1, length(antibody_seq))),
  `rec_age` = rep(mrec_age, 2*length(antibody_seq)),
  `KDPI` = rep(mKDPI, 2*length(antibody_seq)),
  `CIT` = rep(mCIT, 2*length(antibody_seq)),
  `HLA_MM` = rep(mHLA_MM, 2*length(antibody_seq)),
  `GPL_BC_log2` = c(antibody_seq, antibody_seq)
  )

tr <-  posterior_epred(
    model_GFR_MDRD_GPL_BC_interaction_NL_sens,
    newdata = data_prediction)

prediction_ctrl <- tr[, c(1:asl)]

prediction_infliximab <- tr[, c((asl+1):(asl*2))]

prediction <- (
  prediction_infliximab-
     prediction_ctrl
  ) %>% data.frame()


names(prediction) <- c('p05', 'p25', 'p50', 'p75', 'p95')

CIS <- sapply(
  prediction, 
  function(p) quantile(p, probs = c(1/40, 39/40, 0.5, 1e-3, 1-1e-3))
  ) %>% 
  round(1)

CIS
##         p05  p25   p50   p75   p95
## 2.5%   -3.9 -5.3  -7.5 -11.8 -24.1
## 97.5%  17.4  8.9   4.8   1.8   0.7
## 50%     6.7  1.9  -1.3  -5.0 -11.7
## 0.1%  -10.6 -9.0 -11.2 -15.8 -30.5
## 99.9%  24.2 13.6   8.8   6.1   8.5

fig_c <- prediction %>% 
  pivot_longer(values_to = 'value', 
               cols = c('p05', 'p25', 'p50', 'p75', 'p95'),
               names_to = 'GPL_BC_percentile') %>% 
  
  ggplot(aes(y = GPL_BC_percentile, x = value, fill = GPL_BC_percentile)) +
  
  stat_halfeye(.width = c(0.95), slab_alpha = 0.55,
               linewidth = 5,
               shape = 18,
               point_size = 5,
               normalize = "groups",
               p_limits = c(1e-3, 1-1e-3)) +
  
  labs(x = "Effect of infliximab on GFR (mL/min/1.73 m²)", 
         y = 'Percentile of aCL IgG value') +
  
  scale_fill_manual(values = cole, 
                       name = "Percentile of aCL IgG value",
                       breaks = c('p05', 'p25', 'p50', 'p75', 'p95'),
                       labels = c('p05', 'p25', 'p50', 'p75', 'p95')) +
  
  coord_cartesian(xlim = c(-40, 40)) +
  scale_y_discrete(expand = expansion(add = 0.1)) +
  
  
  geom_vline(xintercept = 0, linetype = 2, 
                color = "red", size = 0.6) +
  
  theme(axis.text = element_text(size = 12),
        axis.title = element_text(size = 12)) +
  
  theme(legend.position = "none") +
  
  
  annotate("text",  x = xpos, y = 5.85 , 
           label = paste0("Estimate: ", CIS[3,5]),
           color = cole[5] ) +
  
  annotate("text",  x = xpos, y = 4.85, 
           label = paste0("Estimate: ", CIS[3,4]),
           color = cole[4] ) +
   
  annotate("text",  x = xpos, y = 3.85, 
           label = paste0("Estimate: ", CIS[3,3]),
           color = cole[3] ) +
  
  annotate("text",  x = xpos, y = 2.85, 
           label = paste0("Estimate: ", CIS[3,2]),
           color = cole[2] ) +    
  
  annotate("text",  x = xpos, y = 1.85, 
           label = paste0("Estimate: ", CIS[3,1]),
           color = cole[1] ) +

  annotate("text",  x = xpos, y = 5.5 , 
           label = paste0("95% CI: [", CIS[1,5], ", ", CIS[2,5], "]"),
           color = cole[5] ) + 
  
  annotate("text",  x = xpos, y = 4.5 , 
           label = paste0("95% CI: [", CIS[1,4], ", ", CIS[2,4], "]"),
           color = cole[4] ) + 
  
  annotate("text",  x = xpos, y = 3.5 , 
           label = paste0("95% CI: [", CIS[1,3], ", ", CIS[2,3], "]"),
           color = cole[3] ) + 
  
  annotate("text",  x = xpos, y = 2.5 , 
           label = paste0("95% CI: [", CIS[1,2], ", ", CIS[2,2], "]"),
           color = cole[2] ) + 
  
  annotate("text",  x = xpos, y = 1.5 , 
           label = paste0("95% CI: [", CIS[1,1], ", ", CIS[2,1], "]"),
           color = cole[1] ) 

12.2.3.1 Figure merged

Open code
plotac <- 'sup_figure_6'
path <- "gitignore/figures"


fig <- cowplot::plot_grid(fig_b, fig_c,
  rel_heights = c(0.7, 1),
  labels = c("B", "C"),
  ncol = 1
)

assign(
  plotac,
  cowplot::plot_grid(
    fig_a, fig,
    rel_widths = c(0.6, 1),
    labels = c("A", "")
  )
)

get(plotac)

if (file.exists(paste0(path, "/", plotac, ".pdf")) == FALSE) {
  ggsave(
    path = paste0(path),
    filename = plotac,
    device = "pdf",
    width = 9,
    height = 6
  )
}
Figure 10: Anti-cardiolipin IgG modulation of the infliximab effect on estimated glomerula filtration rate (eGFR) after excluding patients with anti-cardiolipin IgG levels above the maximum in the IFX group. (A) Predicted eGFR by anti-cardiolipin IgG for infliximab (upper) and control (lower) groups with 95% credible intervals (shaded regions) and dashed lines at the 5th, 25th, 50th, 75th, and 95th percentiles of cardiolipin levels. (B) Posterior distribution of the average effects of doubling anti-cardiolipin IgG on eGFR. (C) Posterior distribution of the effect of infliximab on eGFR across anti-cardiolipin IgG percentiles. Results are from a multivariable Bayesian robust regression with B-splines after data restriction.

13 DGF Subgroup analysis by GPL_BC

We will use data divided to patients with under- and above-median value of aCL IgG (GPL_BC)

13.1 Define priors

Open code
priors_subset <- c(
  
  create_prior("GPL_BC_log2",
    2 / sd(data_model_priorImpute$GPL_BC_log2, na.rm = TRUE),
    coef = "GPL_BC_log2"
  ),
   create_prior("IHLA_MMM5",
    2 / sd(data_model_priorImpute$HLA_MM, na.rm = TRUE),
    coef = "IHLA_MMM5"
  ),
  create_prior("IKDPIM50",
    2 / sd(data_model_priorImpute$KDPI, na.rm = TRUE),
    coef = "IKDPIM50"
  ),
  create_prior("Irec_ageM50",
    2 / sd(data_model_priorImpute$rec_age, na.rm = TRUE),
    coef = "Irec_ageM50"
),
  create_prior("ICITM15",
    2 / sd(data_model_priorImpute$CIT, na.rm = TRUE),
    coef = "ICITM15"
  ),
  create_prior("male_sex",
    4,
    coef = "male_sex"
  ),
  create_prior("perfusion_event",
    4,
    coef = "perfusion_event"
  ),
  create_prior("male_sex_donor",
    4,
    coef = "male_sex_donor"
  ),
  create_prior("infliximab",
    4,
    coef = "infliximab"
  ),
  set_prior(paste0("normal(", logit(mean(data_model_priorImpute$DGF)), ", 10)"),
    class = "Intercept"
  )
)

13.2 Fit model for \(<\) median aCL IgG level

Open code
model_dgf_GPL_BC_lowGPLBC <- run(
  expr = brm(
    DGF ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      GPL_BC_log2,
    family = bernoulli(),
    data = data_imputed_lowGPL,
    prior = priors_subset,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 4000, warmup = 2000,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_GPL_BC_lowGPLBC",
  reuse = TRUE
)

summary(model_dgf_GPL_BC_lowGPLBC, robust = TRUE)
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2 
##    Data: data_imputed_lowGPL (Number of observations: 88) 
##   Draws: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
##          total post-warmup draws = 8000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          -1.15      0.88    -2.92     0.57 1.00     6103     5642
## male_sex            0.66      0.61    -0.50     1.88 1.00     7547     5709
## Irec_ageM50        -0.00      0.03    -0.05     0.05 1.00     7614     6063
## male_sex_donor      0.63      0.56    -0.53     1.77 1.00     7908     5889
## IKDPIM50            0.00      0.01    -0.03     0.03 1.00     6795     5914
## ICITM15             0.08      0.04    -0.00     0.16 1.00     7322     6440
## IHLA_MMM5           0.26      0.20    -0.12     0.67 1.00     6960     6236
## perfusion_event    -0.43      0.58    -1.61     0.69 1.00     7869     6343
## infliximab         -1.55      0.57    -2.74    -0.45 1.00     6379     5667
## GPL_BC_log2        -0.49      0.35    -1.22     0.18 1.00     7280     6096
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_GPL_BC_lowGPLBC)
##                           prior     class            coef group resp dpar nlpar
##                          (flat)         b                                      
##     normal(0, 1.41170525720746)         b     GPL_BC_log2                      
##    normal(0, 0.280307006032291)         b         ICITM15                      
##     normal(0, 1.38219051128263)         b       IHLA_MMM5                      
##   normal(0, 0.0970980394231448)         b        IKDPIM50                      
##                    normal(0, 4)         b      infliximab                      
##    normal(0, 0.190589762164436)         b     Irec_ageM50                      
##                    normal(0, 4)         b        male_sex                      
##                    normal(0, 4)         b  male_sex_donor                      
##                    normal(0, 4)         b perfusion_event                      
##  normal(-0.667829372575656, 10) Intercept                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user

tr <- round(exp(fixef(model_dgf_GPL_BC_lowGPLBC, robust = TRUE)[-1, c(1,3,4)]), 2)
colnames(tr)[1] <- 'OR'
kableExtra::kable(tr)
Table 24: Results from multivariable Bayesian logistic regression models examining the main effects of predictors, including infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on delayed graft function (DGF), without interaction terms and including only patients with anti-cardiolipin IgG level below median. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
OR Q2.5 Q97.5
male_sex 1.94 0.61 6.59
Irec_ageM50 1.00 0.95 1.05
male_sex_donor 1.87 0.59 5.88
IKDPIM50 1.00 0.97 1.03
ICITM15 1.08 1.00 1.18
IHLA_MMM5 1.30 0.89 1.96
perfusion_event 0.65 0.20 2.00
infliximab 0.21 0.06 0.64
GPL_BC_log2 0.61 0.29 1.20

13.3 Fit model for aCL \(\geq\) median

Open code
model_dgf_GPL_BC_highGPLBC <- run(
  expr = brm(
    DGF ~
      male_sex +
      I(rec_age - 50) +
      male_sex_donor +
      I(KDPI - 50) +
      I(CIT - 15) +
      I(HLA_MM - 5) +
      perfusion_event +
      infliximab +
      GPL_BC_log2,
    family = bernoulli(),
    data = data_imputed_highGPL,
    prior = priors_subset,
    backend = "cmdstanr",
    seed = 2025,
    cores = 4, chains = 4,
    iter = 4000, warmup = 2000,
    control = list(adapt_delta = 0.95)
  ),
  path = "gitignore/run/model_dgf_GPL_BC_highGPLBC",
  reuse = TRUE
)

summary(model_dgf_GPL_BC_highGPLBC, robust = TRUE)
##  Family: bernoulli 
##   Links: mu = logit 
## Formula: DGF ~ male_sex + I(rec_age - 50) + male_sex_donor + I(KDPI - 50) + I(CIT - 15) + I(HLA_MM - 5) + perfusion_event + infliximab + GPL_BC_log2 
##    Data: data_imputed_highGPL (Number of observations: 89) 
##   Draws: 4 chains, each with iter = 4000; warmup = 2000; thin = 1;
##          total post-warmup draws = 8000
## 
## Regression Coefficients:
##                 Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## Intercept          -2.17      0.82    -3.90    -0.66 1.00     5958     5518
## male_sex            1.56      0.59     0.44     2.78 1.00     6964     5785
## Irec_ageM50        -0.04      0.02    -0.09     0.01 1.00     7544     6006
## male_sex_donor      0.31      0.58    -0.82     1.46 1.00     7261     6549
## IKDPIM50            0.02      0.01    -0.00     0.05 1.00     6958     6417
## ICITM15             0.08      0.04     0.01     0.16 1.00     7101     5523
## IHLA_MMM5           0.33      0.20    -0.05     0.74 1.00     6725     5730
## perfusion_event    -0.96      0.61    -2.22     0.20 1.00     6888     5602
## infliximab          1.06      0.55     0.00     2.16 1.00     7743     6408
## GPL_BC_log2         0.33      0.25    -0.16     0.84 1.00     7068     6138
## 
## Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
prior_summary(model_dgf_GPL_BC_highGPLBC)
##                           prior     class            coef group resp dpar nlpar
##                          (flat)         b                                      
##     normal(0, 1.41170525720746)         b     GPL_BC_log2                      
##    normal(0, 0.280307006032291)         b         ICITM15                      
##     normal(0, 1.38219051128263)         b       IHLA_MMM5                      
##   normal(0, 0.0970980394231448)         b        IKDPIM50                      
##                    normal(0, 4)         b      infliximab                      
##    normal(0, 0.190589762164436)         b     Irec_ageM50                      
##                    normal(0, 4)         b        male_sex                      
##                    normal(0, 4)         b  male_sex_donor                      
##                    normal(0, 4)         b perfusion_event                      
##  normal(-0.667829372575656, 10) Intercept                                      
##  lb ub  source
##        default
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user
##           user

tr <- round(exp(fixef(model_dgf_GPL_BC_highGPLBC, robust = TRUE)[-1, c(1,3,4)]), 3)
colnames(tr)[1] <- 'Odds ratio'
kableExtra::kable(tr)
Table 25: Results from multivariable Bayesian logistic regression models examining the main effects of predictors, including infliximab treatment and log2-transformed anti-cardiolipin IgG (GPL_BC_log2), on delayed graft function (DGF), without interaction terms and including only patients with anti-cardiolipin IgG level at/above median. The odds ratio (OR) represents the estimated change in the odds of DGF per one-unit increase in the predictor. OR: odds ratio; Q2.5 and Q97.5: lower and upper bounds of the 95% credible interval, respectively.
Odds ratio Q2.5 Q97.5
male_sex 4.754 1.548 16.143
Irec_ageM50 0.964 0.918 1.012
male_sex_donor 1.361 0.440 4.314
IKDPIM50 1.024 0.996 1.055
ICITM15 1.083 1.008 1.179
IHLA_MMM5 1.387 0.950 2.098
perfusion_event 0.382 0.108 1.218
infliximab 2.897 1.005 8.695
GPL_BC_log2 1.397 0.855 2.324

15 Reproducibility

Open code
sessionInfo()
## R version 4.4.3 (2025-02-28)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 22.04.5 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0 
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=cs_CZ.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=cs_CZ.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=cs_CZ.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=cs_CZ.UTF-8 LC_IDENTIFICATION=C       
## 
## time zone: Europe/Prague
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] bayestestR_0.14.0 mice_3.17.0       ggbeeswarm_0.6.0  quantreg_5.98    
##  [5] SparseM_1.81      coxed_0.3.3       survival_3.7-0    rms_6.8-1        
##  [9] Hmisc_5.1-3       bayesplot_1.8.1   ggdist_3.3.2      kableExtra_1.4.0 
## [13] lubridate_1.8.0   corrplot_0.92     arm_1.12-2        lme4_1.1-35.5    
## [17] MASS_7.3-64       janitor_2.2.0     projpred_2.0.2    brms_2.21.0      
## [21] Rcpp_1.0.13       glmnet_4.1-8      Matrix_1.7-0      boot_1.3-31      
## [25] cowplot_1.1.1     pROC_1.18.0       mgcv_1.9-1        nlme_3.1-167     
## [29] openxlsx_4.2.5    flextable_0.9.6   sjPlot_2.8.16     RJDBC_0.2-10     
## [33] rJava_1.0-6       DBI_1.1.2         car_3.1-2         carData_3.0-5    
## [37] skimr_2.1.5       gtsummary_2.0.2   emmeans_1.10.4    ggpubr_0.4.0     
## [41] stringi_1.7.6     forcats_1.0.0     stringr_1.5.1     dplyr_1.1.4      
## [45] purrr_1.0.2       readr_2.1.2       tidyr_1.3.1       tibble_3.2.1     
## [49] ggplot2_3.5.1     tidyverse_1.3.1  
## 
## loaded via a namespace (and not attached):
##   [1] fs_1.6.4                matrixStats_1.3.0       httr_1.4.2             
##   [4] insight_0.20.2          repr_1.1.7              tools_4.4.3            
##   [7] backports_1.5.0         sjlabelled_1.2.0        utf8_1.2.4             
##  [10] R6_2.5.1                jomo_2.7-3              withr_3.0.1            
##  [13] Brobdingnag_1.2-7       prettyunits_1.1.1       gridExtra_2.3          
##  [16] cli_3.6.3               textshaping_0.3.6       performance_0.12.2     
##  [19] gt_0.11.0               officer_0.6.6           sandwich_3.0-1         
##  [22] labeling_0.4.2          sass_0.4.9              mvtnorm_1.1-3          
##  [25] polspline_1.1.25        ggridges_0.5.3          askpass_1.1            
##  [28] QuickJSR_1.3.1          systemfonts_1.0.4       commonmark_1.9.1       
##  [31] StanHeaders_2.32.10     foreign_0.8-88          gfonts_0.2.0           
##  [34] svglite_2.1.3           readxl_1.3.1            rstudioapi_0.16.0      
##  [37] httpcode_0.3.0          generics_0.1.3          shape_1.4.6            
##  [40] distributional_0.4.0    zip_2.2.0               inline_0.3.19          
##  [43] loo_2.4.1               fansi_1.0.6             abind_1.4-5            
##  [46] lifecycle_1.0.4         multcomp_1.4-18         yaml_2.3.5             
##  [49] snakecase_0.11.1        grid_4.4.3              promises_1.2.0.1       
##  [52] crayon_1.5.0            mitml_0.4-3             lattice_0.22-5         
##  [55] haven_2.4.3             pillar_1.9.0            knitr_1.48             
##  [58] estimability_1.5.1      codetools_0.2-19        pan_1.6                
##  [61] glue_1.7.0              V8_4.4.2                fontLiberation_0.1.0   
##  [64] data.table_1.15.4       vctrs_0.6.5             cellranger_1.1.0       
##  [67] gtable_0.3.0            assertthat_0.2.1        datawizard_0.12.2      
##  [70] xfun_0.46               mime_0.12               coda_0.19-4            
##  [73] iterators_1.0.14        ellipsis_0.3.2          TH.data_1.1-0          
##  [76] fontquiver_0.2.1        rstan_2.32.6            tensorA_0.36.2.1       
##  [79] vipor_0.4.5             rpart_4.1.24            colorspace_2.0-2       
##  [82] nnet_7.3-20             tidyselect_1.2.1        processx_3.8.4         
##  [85] compiler_4.4.3          curl_4.3.2              rvest_1.0.2            
##  [88] htmlTable_2.4.0         xml2_1.3.3              fontBitstreamVera_0.1.1
##  [91] posterior_1.6.0         checkmate_2.3.2         scales_1.3.0           
##  [94] callr_3.7.6             digest_0.6.37           minqa_1.2.4            
##  [97] rmarkdown_2.27          htmltools_0.5.8.1       pkgconfig_2.0.3        
## [100] base64enc_0.1-3         dbplyr_2.1.1            fastmap_1.2.0          
## [103] rlang_1.1.4             htmlwidgets_1.6.4       shiny_1.9.1            
## [106] farver_2.1.0            zoo_1.8-9               jsonlite_1.8.8         
## [109] magrittr_2.0.3          Formula_1.2-4           munsell_0.5.0          
## [112] gdtools_0.3.7           plyr_1.8.6              pkgbuild_1.3.1         
## [115] parallel_4.4.3          sjmisc_2.8.10           ggeffects_1.7.0        
## [118] splines_4.4.3           hms_1.1.1               sjstats_0.19.0         
## [121] ps_1.7.7                uuid_1.0-3              ggsignif_0.6.3         
## [124] markdown_1.13           reshape2_1.4.4          stats4_4.4.3           
## [127] rstantools_2.1.1        crul_1.5.0              reprex_2.0.1           
## [130] evaluate_1.0.0          RcppParallel_5.1.8      modelr_0.1.8           
## [133] nloptr_2.0.0            tzdb_0.2.0              foreach_1.5.2          
## [136] httpuv_1.6.5            MatrixModels_0.5-3      cards_0.2.2            
## [139] openssl_1.4.6           cardx_0.2.1             broom_1.0.6            
## [142] xtable_1.8-4            rstatix_0.7.0           later_1.3.0            
## [145] viridisLite_0.4.0       ragg_1.2.1              beeswarm_0.4.0         
## [148] cluster_2.1.8           gamm4_0.2-6             cmdstanr_0.8.0.9000    
## [151] bridgesampling_1.1-2

References

Bürkner, Paul-Christian. 2017. Brms: An r Package for Bayesian Multilevel Models Using Stan 80. https://doi.org/10.18637/jss.v080.i01.
Makowski, Dominique, Mattan S. Ben-Shachar, and Daniel Lüdecke. 2019. “bayestestR: Describing Effects and Their Uncertainty, Existence and Significance Within the Bayesian Framework.” Journal of Open Source Software 4 (40): 1541. https://doi.org/10.21105/joss.01541.
R Core Team. 2024. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
van Buuren, Stef, and Karin Groothuis-Oudshoorn. 2011. “Mice: Multivariate Imputation by Chained Equations in r.” Journal of Statistical Software 45 (3): 1–67. https://doi.org/10.18637/jss.v045.i03.